# Biquad Filters (DSP with STM32) - Phil's Lab #172

## Метаданные

- **Канал:** Phil’s Lab
- **YouTube:** https://www.youtube.com/watch?v=rDERCmBAv3I
- **Дата:** 08.04.2026
- **Длительность:** 26:27
- **Просмотры:** 7,712

## Описание

Theory and implementation of digital, discrete-time biquad filters on an STM32-based audio-processing system.

Limited-time: $2 for 6-layer PCBs up to 100×100 mm - grab your $33 coupon now: https://jlcpcb.com/events/6-layer-pcb?from=PhilsLab (Ad)

OSHWLab Stars 2026: https://oshwlab.com/activities/stars2026

Altium Develop: http://altium.com/yt/philslab (Ad)

[SUPPORT]
Hardware design courses: https://phils-lab-shop.fedevel.education
Course content: https://www.phils-lab.net/courses
Patreon: https://www.patreon.com/phils94

[LINKS]
DSP Playlist: https://www.youtube.com/playlist?list=PLXSyc11qLa1ZCn0JCnaaXOWN6Z46rK9jd

[TIMESTAMPS]
00:00 Intro

02:02 JLCPCB (Ad)
03:37 Altium Develop (Ad)

04:42 Basics
07:02 Why use Biquads?
08:35 Transposed Direct Form II
09:58 Difference Equations
12:58 Computing Coefficients

15:33 Implementation
23:09 Lowpass Filter Test (2nd Order)
24:47 Cascading Biquads (4th Order LPF)

25:59 Outro

## Содержание

### [0:00](https://www.youtube.com/watch?v=rDERCmBAv3I) Intro

In this video, we're going to explore I quad filters as they apply to digital signal processing in the discrete time digital domain. We're going to go all the way from the theory and basics looking at block diagrams and transfer functions through to a real world quasi real-time implementation running on a custom bit of hardware that is an STM32based guitar pedal where we'll be processing audio and we can test these biquad filters how they apply for instance to equalizers in audio such as low pass filters, highp pass filters and so on. We'll look at implementation details such as different implementation forms, stability issues, floating point versus fixed point, and how we can adapt filter coefficients on the fly in case you want to change filter parameters. By quads themselves are essentially second order IR filters and probably the single most important building block in digital audio and DSP, at least as it applies to filters. They're used in nearly all audio effects, equalizers, crossovers, and so on. You can use them as single building blocks or cascade them together. Their computation is cheap, individually stable if you design them right. And changing and cascading them in series allows you to construct high order filters, low pass, high pass, band pass, notch, peaking, and so on. Hopefully this video provides a good introduction and you can use these filters in your own designs. Later on, then we will be of course implementing the by quad filters after we've covered the theory on a quasi real-time embedded system. And we've seen this in many videos previously. This is an STM3287based digital guitar processing platform. a single mono input, single mono output, an SCM3287 processor which we'll be coding using C a 24-bit 48 kHz audio codec with an analog front analog back end which we can then also control using various potentiometers and we'll map some of these for instance to gain cut off frequency and Q values of the filters we later on then implement for this video I am assuming some prerequisite knowledge I do have a pretty lengthy DSP playlist on my channel which I'll leave links to in the description box below which also covers some of a setup for the hardware we'll be using in this video. I'd strongly suggest watching video number 20, number 46, number 55, and video 89 just to give you the prerequisite knowledge you might need for this video. A huge thank you to

### [2:02](https://www.youtube.com/watch?v=rDERCmBAv3I&t=122s) JLCPCB (Ad)

JLC PCB for sponsoring this video. I have most of my PCBs manufactured at JLCPCB and they always do a fantastic job. In particular, I would like to shout out the high precision six layer PCB service. Six layer PCBs give you access to more routin layers of course than two or four layers. increases your routing efficiency. You can have dedicated ground and power planes on extra signal layers, giving you faster development cycles, cleaner design, and fewer redesigns. Typically, JLC PCB helps us out as designers because of an unbeatable price. For instance, for a six layer PCB, 50x 50 mm, we can get them right now at $2 for five pieces. And this includes an immersion nickel gold surface finish. We can specify impedance control and we get epoxy filled and capped V as a standard. So we can do VN pad again just for $2 for 50 by 50 mm PCBs. They're also very efficient and very quick to manufacture the PCBs. Oftent times I can have my PCBs back in less than 2 weeks and this is also with assembly. Also at the time of making this video, EZEDA and the open source hardware lab with manufacturing support from JLCPCB is running the OSHW lab stars 2026 open source PCB design competition. This contest focus on the full journey of design, prototyping, real world applications, and then open-source sharing. They have prizes up to 85,000 total in cash, material, and shipping support from JLCPCB, and $100 JLC PCB coupon for every completed project. Also, the top creators are invited to the open source hardware lab stars conference in 2027. I'll leave a link to this in the description box below. Make sure to check it out and join if you want to. A huge thank you

### [3:37](https://www.youtube.com/watch?v=rDERCmBAv3I&t=217s) Altium Develop (Ad)

also to Alum for sponsoring this video. I use Alim develop which includes Aluminum Designer and Alim 365 in my everyday day-to-day work life as well as for creating content for this channel and also use Alim Designer as part of Alton Develop to design and manufacture this digital audio processing board that we'll be seeing and using in this particular video. Alimin develop enables multiddisciplinary teams to design, develop and manufacture highquality hardware products with ease and efficiency all the way from co-creation of designs be that parts library management, schematic design, hardware design, requirements management, all the way through managing your supply chain, manufacturing and of course generating and maintaining all of the relevant data as part of an entire project. You can take a tour of Alton Develop and I'll leave links to this in the description box below which guides you through all of the parts that Alton Develop helps you manage in your project and product design process if you're interested. Again, I'll leave links in the description box below, but you can get started with Alton Develop and you can try this out for yourself risk-f free for 30 days. Links will be in the description box below. Bquad filters in

### [4:42](https://www.youtube.com/watch?v=rDERCmBAv3I&t=282s) Basics

their digital basic form are rather simple, but they're incredibly useful as we'll see. Bquad filters are a standard building block. second order digital infinite impulse response filter or IR filter for short. They are comprised of two poles, two zeros and an adjustable gain and in the most basic transfer function form where we have normalized coefficients. We can see the transfer function here. So the relationship in the Z domain between the output and the input we can see that this gives actually rise to the name of by quad. So by a quadratic filter we have a second order polinomial a quadratic equation in the numerator which then tells us the location of the zeros and in the denominator we also have a quadratic equation. So a second order polinomial where the solutions of that polomial give rise to the poles of this biquad filter. So we have two zeros and two poles and this form again is with the coefficients normalized. So typically instead of the one in the denominator we would have a z but a lot of the times we divide all of the coefficients by a z leaving us only with five coefficients. So a normalized by quad filter. This is the transfer function we'll be using to derive the difference equations later on. On the right hand side you can see the equivalent simple direct form one block diagram where we have four delays. These are indicated by the z to the minus1 blocks. We have five gains. So b to b2 and a1 a2. Those are the various coefficients. We have three adders and of course various multiplies at the junctions. We'll see later on that this actually can be simplified and we can derive various forms of a biquad filter which are useful for various different types of implementation. If it's a fixed point, floating point and so on. The nice thing about biquad filters and why we're even concerning ourselves with such a generic form is that pretty much any I filter type can be realized using one or more by quads in series. That means they are cascaded. We can generate highp pass filters, low pass filters, bandp pass filters, notches and pretty much any combination of these simply by cascading and using standard equations for to derive the coefficients for this bioquad filter. In addition, IRL filters in general and in particular these second order ones are very computationally efficient. In its basic form, we only have a couple of multiply accumulates and we only have to store four delay memories. We'll see later on that this might be just a naive straightforward implementation and we can actually reduce that down by transposing the biquad filter block

### [7:02](https://www.youtube.com/watch?v=rDERCmBAv3I&t=422s) Why use Biquads?

diagram. You might be wondering, we've seen different filters, different IR filters in previous videos and so far we haven't used by quads at least directly and there's good reason to use by quads and typically we will use by quads in many DSP applications that require these types of filters in particular if we need higher order IR filters. These often times suffer from stability and accuracy issues and this is mainly due to the fact that we have finite precision in the way we represent numbers digitally. So if that's fixed point or if that's floating point we have only so many bits that we can use to represent a number. Therefore we'll have rounding errors, quantization errors and that can actually cause instability in particular in high order filters but even in lower order ones as well assuming you have for instance pole locations very close to the unit circle in the Z domain or on the Z plane. Any quantization could shift those poles outside of the unit circle or even not and that causes instability in the filter. Also in particular this issue manifests itself for low frequency and high frequency poles relative to the sample rate of course where poles are inherently near the unit circle. The nice thing is then again why we would want to use by chords is that by chords allow for stability per block. So we have these rather simple second order IR filters given of course that the poles are within a unit circle and these can then be cascaded these stable blocks to form higher order filters and an illustration is shown below where we have three second order by quad low pass filter sections. we can cascade them. So fade the output of one into the input of the next to give us a higher order filter. If you want an odd order filter, you can of course cascade a biod with a first order IR filter to give you odd order filters. We previously saw the

### [8:35](https://www.youtube.com/watch?v=rDERCmBAv3I&t=515s) Transposed Direct Form II

most basic or naive simplistic implementation or block diagram of a byquad filter and that is called the direct form one. We can derive different forms of the byquad filter and one that is quite interesting for us because we work a lot on floatingpoint systems is the transpose direct form too. We won't go through the deration of how you can arrive at this new block diagram here. There's plenty of information in books and on the internet if you're interested. This particular form the transpose direct form two is shown in the block diagram in the center. And this is very useful for us again for instance for floating point implementation. Rather than four delay blocks, we now only have two delay blocks and we're using internal state variables rather than keeping memories or copies of the memory of input and output samples. This form, although it looks different in the block diagram, if you actually work through the nodes, you'll see that this is mathematically equivalent to the direct form one. It's the same transfer function, but we arrive at different difference equations. Now, again, we only have two state variables, so two delays, which means we have less memory. We have fewer memory accesses which can improve performance both in terms of size and speed. And the nice thing is with this transpose direct form 2 that the internal states so essentially the states at the delay outputs are typically closer in magnitude to each other compared to direct form one. This helps us when we're adding numbers together because numbers closer in magnitude typically have a higher accuracy for instance with floating

### [9:58](https://www.youtube.com/watch?v=rDERCmBAv3I&t=598s) Difference Equations

point. The natural question is then how do we implement any of these forms of the biquad filter? Because we want to of course implement them on a digital system typically in code and we will be using C later on. As usual with IR filters, the actual implementation is rather straightforward. All we have to do is convert the transfer function from the Z domain to the time domain or even easier we just follow the block diagram and then create difference equations. Starting from the block diagram for the transpose direct form 2 by quad filter. We can see on the right hand side we have x as our input y is our output and I've just noted down two internal states. That's w1 for the first delay state and w2 for the second delay state. We have our coefficients as before. So b1 b2 and a1 a2 as we saw from the transfer function. From that we can then very easily derive these three difference equations. The current output which is y of n. So at sample n is b * x of n which is our current input plus the internal state 1 which is w1. W1 we then compute with a second difference equation and w2 we compute with this equation at the bottom. And these computations have to be in order. You can see very simple. We only have two internal states. We take the input and the output. We do a couple multiply ads and that's about it. Initially unless we have reason to otherwise we would set the internal states w1 and w2 equal to zero. Some notes on implementation. Again, regardless of the form, if you're using direct form one, if you're using transpose direct form 2, or any other form at very low frequencies and at high sample rates, it can also be beneficial rather than to use single precision. So, typically 32-bit floatingoint variables to use double precision instead. Often times, modern processors, especially DSPs, might natively have hardware support for 64-bit or dual precision or double precision floatingoint numbers. And that can be beneficial because again we might have pole placements close to the unit circle which with quantization rounding error can slip outside the unit circle. And typically with these multiplications which we have here, multiplications typically generate more intermediate bits of which we then lose that information when we're truncating when we need to store multiplication results back into memory. That also gives quantization errors. While single precision floating points often times sufficient, some examples might lend themselves to double precision, especially if you have a double precision floating point unit within your system and enough memory to spare. Another thing to watch out for, and we'll see later on how to mitigate that, is that we shouldn't have sudden changes of coefficients. The nice thing about IR filters is that you can change them on the fly. You can update the coefficients on the fly. If you want to change parameters of a filter, that might be cut off frequency, Q values, and so on. these sudden changes, especially the large changes because you're accessing the coeffic coefficients directly which directly impact the internal states that can cause large transients. It can cause instability which of course is problematic. Instead, you could if you're planning on changing coefficients, you could have two filter instances and you can crossfade their outputs and then switch over to the new filter coefficients or you can ramp the filter coefficients from an initial value to a target every update cycle. There's different ways of changing coefficients rather than having these impulses. You're probably also wondering

### [12:58](https://www.youtube.com/watch?v=rDERCmBAv3I&t=778s) Computing Coefficients

how even do we get these coefficients this B nor B1 B2 A1 and A2 how do we calculate those you could go through the maths yourself but there are three methods I would like to highlight one is coming from analog prototype for example on the right hand side we have this salon key or this VCVS second order low pass filter we can write down the differential equations convert them to the LLAS transform or discretize them directly and then we can get the coefficients based on an analog prototype based on the values of R C which translate to cut off frequency and Q values. We've seen this before in many different videos. There are various different discretization methods such as ola transform by line transform and so on. This has been done time and time again. So there are many books and online resources such as the audio EQ cookbook, various websites that actually give you equations for different filter types or we just simply use an online calculator and I'll show you one in just a second. I really like this earlevel. com website. This calculator allows you to select the filter type, various plot options, what sample rate you're running at, what filter parameters you're running at, for example, the cutff frequency, the Q values and gains, and then spits out the coefficients for numerator and denominator. Keep in mind that typically the numerator coefficients are B with a subscript and the denominator coefficients are A with a subscript what actually flips them around. So the A coefficients are zeros, B coefficients are poles to make sure you map them correctly to the right coefficients. But in any case, you could choose a low pass filter. You type in your sample rate and you can change the cutff frequency. And you can see the coefficients change as we adjust the cutff frequency as well as the Q value. We can see we're changing the peak and the phase response. But we can use this calculator take over these coefficients into our program. If we want a fixed filter where we don't want to change the parameters on the fly for this, this might be a good tool to use. Otherwise, there are also many different application notes, books that will actually give you design equations which we can then use in code to update the filter parameters in real time based on these equations. Again, we can see the transfer function for a second order filter. B terms on the top to do with the zeros, A terms on the bottom, denominator to do with the poles and their various different design equations. For lowass filters, we want to do a second order filter. We premputee these various terms and from those premputed terms, we can calculate the coefficients for our filters. very straightforward. I suggest going this route if you want to have your filters adjustable on the fly. There's low pass highp pass filters, parametric EQ and so on. There's also the audio EQ cookbook which goes also more into theory of direct from one, direct from two and so on and gives you various equations for the type of filters you might be encountering. Now that we've

### [15:33](https://www.youtube.com/watch?v=rDERCmBAv3I&t=933s) Implementation

gone through the theory and essentials of what biquad filters are, why you might use them, and also how to get the coefficients for these filters, let's go over to an actual realworld embedded platform and implement a biquad filter. I'm going to be using hardware we've seen many times on this channel. This is this mono guitar pedal based on an STM3287 processor. This is where our code will be running on. It interfaces with a Sirrus Logic codec. has an analog front end, analog back end where we can then run an input signal into this device, get an output signal and we can actually perform proper measurements such as bodhi plots on the real world hardware to see if our bquad filter on the real world implementation matches up to our theoretical expectations. I also have various controls such as potentiometers that I can use that are fed into the ADC channels of the SM3287 which we can then control and adjust filter parameters with. So let's implement the code next. I won't be going through the I squareds, DMA, and general STM32 setup in this particular video. I've done this before, in particular in video number 55 on my channel. I strongly suggest checking that out if you're unfamiliar with setting up an audio stream with a codec through an STDM32 platform that goes through everything in detail. We will just be looking at the biquad implementation in this particular video. Here's the code for the Bquad filter. I've just done this as a pair ofh and C files which I can then tie in and reuse. I can instantiate many of these by quad strcts. For instance, if I want to cascade or I want to have different bods running on different channels, I can do that with a very generic class. The core of this is the byquad strct itself. This contains the coefficients. So, a1 and a2 for the denominator and b1 b2 for the numerator. We also need to store the internal states. So, w1 and w2. And we can also store the output just for simplicity and for access. You'll also have noticed that I have a essentially a copy of the coefficients with an underscore t and these are the target coefficients because I'm implementing a very simple form of smoothing when I update my coefficient values. Essentially low pass filtering from the current values to the target coefficients. But if you don't want to implement smoothing, all you need are the current coefficients, the internal states and if you want of course the output. I then have various functions. One is the initialize function which sets the current coefficients. It sets the internal states and then clears the output. We have a set coefficient function which can be used to set the target coefficients or the actual coefficients themselves within the strct which just a one function call. I have an example set lowass function where instead of coefficients such as a1, a2, b and so on, I take in a cut frequency, a q value and a sampling frequency and then compute the coefficients and set the coefficients and this is taken from an st app node and some equations but we'll go through that later on. Depends on what you want to implement if it's low pass, high pass and so on. The most important or function important is the update function where we take an input sample and generate an output sample based on the difference equations we saw in the slides. Going through the initialization function, we take in the strct by reference. We initially just set the coefficients to be pass through because a n is one. So the denominator would be one if we set a1 and a2 to zero. And all we have to do is set b n to one. And that gives us a pass through strct. In case we've turned on coefficient smoothing, we set the targets to the same values. We clear the state variables to zero and the output variables and the output variable to zero. This is just called once when we start up our program. Set coefficients essentially just takes all the arguments and sets them to the strct. The update function itself just takes an input sample and then if we just look at the calculation section we can see in you can see in comments I've added in the three difference equations and what we're computing. We have three difference equations we have to calculate. The output is B * the input plus plus the state of W1. W1 is this difference equation. So B1 * the input minus A1 * the current output plus the state of W2. And then we compute W2. W2 is B2 * the input minus A2 * the current output. After we've computed these three difference equations, all we have to do is return the current filter output. If you want to implement smoothing to try and avoid or reduce sudden coefficient jumps, we can just do a simple first order IR lowass filter where we have a target value, for instance, target of the A1 coefficient. We multiply that by some sort of smoothing coefficient and add that to one minus the smoothing coefficient times the current value of our coefficient A1. We only run that smoothing filter if there is a significant difference between the current coefficient and the target coefficient. Now, this might be a rather crude way of smoothing or going from the current coefficient value to your target coefficient value, but it's something that works fairly well in practice. You of course need to do this for all of the coefficients within the filter. And there are five coefficients for this particular bio quad filter. So, we're checking if there's a significant difference for every coefficient and the target. If there is, we just perform the smoothing and we slowly ramp from a current value to the target value based on the smoothing coefficient. Now you can take that out and you can just set the coefficients directly. But keep in mind that this could cause transients and instability for large coefficient changes because that disrupts the internal states as well. Again, another option would be just to crossfade or blend between two different filter instances. And once you've blended, you just continuously compute the new filter instance. That would be a different way of achieving this as well. You will have noticed we also jumped over the set lowass function. This is an optional function. It depends on what kind of filters you want to implement. We want a function on the fly. If we're turning a potentiometer, if we're updating the cut off frequency of a low pass filter or the Q value or whatever, we want to have the functions, the equations integrated into our program that recomputes the coefficients on the fly based on certain equations. And in this case, the lowass filter equations I took from the application note we just saw, AN2874 from ST micro electronics. the low pass filter design equations. I just took these premputee values and then computed the coefficients A1 A2 and B1 B2. That's exactly what I took over here. And then I just call the set coefficient function just for the sake of simplicity. Keep in mind there are some somewhat expensive computations in there. So for example, calling 10 function might be expensive. So you wouldn't want to do that every single sample. You might want to do approximations or use different equations. But just for the sake of simplicity, I've just implemented this set lowass which implements these equations and sets the coefficients. Then in my main functions to include the low pass filter, I'm including my bike quad. Before starting the audio stream, I call the initialization function for the bquad. And in my process function, I'm reading once per block the current potentiometer values and mapping them to a cutter frequency in hertz to the Q value. And I have some preggain and some post gain, which is just a multiplication before the filter and after the filter. So nothing to do with the bord. And this is to demonstrate. Then I'm calling the set lowass function again once per block. And through looping through every sample I'm computing my current output by calling the bquad update function passing in the filter strct my reference and sending in my current input sample just premultiplied with a volume between 0 and 1. And I'm getting my output which is also multiplied by a post volume. And just for the sake of if we have large Q values that might clip our plus minus one range which we have in this particular system. So that's why I can just vary the gains before I feed into the filter and after my result I get out of the filter. So very simple, I call the initialization function. I call the compute coefficient function. In this case, we're just using a low pass filter, calling the update function on every sample and getting that output and feeding that to the DAC later on. Let's move over and see if this filter, this low pass filter actually does what it's supposed to do. Cut off frequency range is from 1 kHz to 6 kHz. And the Q value is from critically damped, so one over roo< unk>2 to about a Q value of five. And I have my pre and post gain anywhere from zero to one linear. With the code

### [23:09](https://www.youtube.com/watch?v=rDERCmBAv3I&t=1389s) Lowpass Filter Test (2nd Order)

uploaded to this guitar pedal PCB and running on the SM3287, we have a single B quad instance running as a lowass filter using the coefficients we computed using the ST micro electronics application node for a second order lowass filter with variable cutff frequency and variable Q control. As we can see here, I'm using a Quantisylm QA43 audio analyzer, sending an output of the analyzer to the input of my guitar pedal and taking the output back into the quantile. So, we can do nice bod plots. And this is the bod plot of the magnitude response with a filter running. On the right hand side in the background, you can see I have my variable plots of the various filter parameters based on the potentiometer settings. So, currently I have my cut off frequency at 1,000 hertz, Q at about 1 over < unk>2, volume pre, volume post at about one. Keep in mind the fluctuations in these floating boat values is because the pots are pretty much just taken raw with a slight bit of filtering. At a cutter frequency of 1 kHz, we can see at a minus 3dB point, we are exactly at 1 kHz. Now, if I adjust my potentiometer for the cutter frequency, let me just move that up. Let's just move it to 2 kHz. I'll try and aim looking at the right hand side. So, FC of two. We have of course have some update delay because we are running averages the QA43 but of course actually the update is pretty much instantaneous on the pedal itself. Now with the color frequency of 2 kHz after my 3dB point has moved to 2 kHz. So that's looking pretty good. Now if I adjust my Q value, let's adjust that to higher. We can see the filter gets more and more peaky. So now we're getting a peak before we dip down around the cut off frequency. and we increase that peak higher and higher which looks to be confirming that our filter equations are correct and also the equations to calculate the various coefficients given that this is a biquad

### [24:47](https://www.youtube.com/watch?v=rDERCmBAv3I&t=1487s) Cascading Biquads (4th Order LPF)

filter as we talked about we can just simply cascade them to get higher order filters let's do exactly that so I've created an array of bquad filters we're just going to do a fourth order filter so that's two by quad filters in series and we'll just keep the same lowass filter type with the same coefficients so I create two of these strcts I initialize them both before the audio stream start. I compute the output of my first biquod filter by passing the input. I then compute the output of my second bod filter by passing the output of the previous biquad filter. And then I just set the output to be the output of my second bioquad filter. In terms of computing coefficients, I compute the same coefficients for both. And I set So it's just a fourth order filter. And now let's upload that to the board. And now with this fourth order border, I've set my cutter frequency back to 1 kHz. Q of 1 over < unk>2. We can see at 1 kHz the cut off frequency we are now at minus 6 dB for this fourth order filter and we have a steeper transition band again because this is a higher order filter. So this is how easily you can then cascade various by quad filter types. You can mix and match whatever structure you're trying to come up with at the end and to build up higher order filters which are less prone to these stability issues. Thank you very much for watching

### [25:59](https://www.youtube.com/watch?v=rDERCmBAv3I&t=1559s) Outro

this video. I hope it was useful and I hope it showed you the basics of biquad digital filters used for digital signal processing. What the applications are and why you might use them and then how you can also use them on real-time embedded systems for instance for processing audio data as shown in this video. If you like the video, please leave a like, a comment if you have any questions and don't forget to subscribe to stay up to date with any latest PCB design, hardware design, and embedded systems videos. Thanks again for watching and I hope to see you in the next one. Bye-bye.

---
*Источник: https://ekstraktznaniy.ru/video/51807*