filter

Bandwidth of some bandpass filters

October 18, 2025 math and physics play , , , , , , , , , , , , ,

[Click here for a PDF version of this post]

Karl had a couple of fun filter problems that he chatted with me about. I didn’t remember how do find the bandwidth, nor the resonant frequency of such a circuit, and after he solved the problems, I tried them for myself.

The circuits, as seen in fig. 1, were RC and RL respectively, and both ended up having the same transfer function.

fig 1a. RC bandpass filter.

fig 1b. RL bandpass filter.

 

For my attempt to solve these circuits, I used the loop current method that Karl recently taught me. Perhaps I once knew that method, but if I had, I’d forgotten. This loop method can be nicer than a standard nodal analysis, since it can automatically eliminate some current variables. Here’s the equations for the RC circuit
\begin{equation}\label{eqn:RLCbandwidth:20}
\begin{aligned}
V_a – V_s &= I_1 (1) \\
V_a &= (I_1 – I_2) \inv{s} \\
V_o – V_a &= I_2 \inv{s} \\
V_o &= I_2 (1).
\end{aligned}
\end{equation}
The equations for the RL circuit are
\begin{equation}\label{eqn:RLCbandwidth:40}
\begin{aligned}
V_a – V_s &= I_1 s \\
V_a &= (I_1 – I_2) (1) \\
V_o – V_a &= I_2 (1) \\
V_o &= I_2 s.
\end{aligned}
\end{equation}
The transfer functions for both is
\begin{equation}\label{eqn:RLCbandwidth:60}
H(s) = \frac{V_o}{V_s} = \frac{1}{1/s + 3 + s}.
\end{equation}
A plot of \( \Abs{H(j\omega)} \) can be found in fig. 2, and peaks at \( \omega = 1 \).

fig. 2. Transfer function.

 

Observe that the denominator of this transfer function looks just like a series RLC impedance. For example, for the circuit of fig. 3, we have
\begin{equation}\label{eqn:RLCbandwidth:80}
\frac{I}{V} = \inv{Z} = \inv{ R + L s + \inv{s C} }.
\end{equation}

fig. 3. RLC circuit.

 

Written out in the frequency domain, that impedance is
\begin{equation}\label{eqn:RLCbandwidth:100}
Z(\omega) = R + j \lr{ \omega L – \inv{\omega C} }.
\end{equation}
Max power transfer through this circuit will be for the specific frequency where the impedance is purely real. In this case, that is the frequency \(\omega_0\) that satisfies
\begin{equation}\label{eqn:RLCbandwidth:120}
\omega_0^2 = \inv{L C}.
\end{equation}
Karl’s textbook didn’t define bandwidth in any general sense, but did do so for an RLC circuit of this form, stating that the bandwidth was \( \omega_2 – \omega_1 \) where these are the frequencies of the half (average) power points.

We need to remind ourselves what the formula for average power is
\begin{equation}\label{eqn:RLCbandwidth:140}
\begin{aligned}
P
&= \inv{T} \int_0^T v(t) i(t) dt \\
&= \inv{T} \int_0^T \textrm{Re} \lr{ V e^{j\omega t} } \Real \lr{ I e^{j\omega t} } dt \\
&= \inv{4 T} \int_0^T
\lr{ V e^{j \omega t} + \bar{V} e^{-j\omega t} }
\lr{ I e^{j \omega t} + \bar{I} e^{-j\omega t} } dt \\
&= \inv{4} \lr{ V \bar{I} + \bar{V} I } \\
&= \inv{2} \textrm{Re} \lr{ V \bar{I} } \\
&= \inv{2} \textrm{Re} \lr{ I Z \bar{I} } \\
&= \inv{2} \Abs{I}^2 R \\
&= \inv{2} \Abs{V}^2 \frac{R}{\Abs{Z}^2}.
\end{aligned}
\end{equation}
The maximum average power is for purely real impedance
\begin{equation}\label{eqn:RLCbandwidth:160}
P = \inv{2 R} \Abs{V}^2,
\end{equation}
so the half power points are when \( \Abs{Z} = \sqrt{2} R \). For the RLC circuit that is when
\begin{equation}\label{eqn:RLCbandwidth:180}
\Abs{R + j \lr{ \omega L – \inv{\omega C} }}^2 = 2 R^2,
\end{equation}
or
\begin{equation}\label{eqn:RLCbandwidth:200}
R^2 = \lr{ \omega L – \inv{\omega C} }^2.
\end{equation}
We seek solutions for
\begin{equation}\label{eqn:RLCbandwidth:220}
\begin{aligned}
R &= \omega L – \inv{\omega C} \\
-R &= \omega L – \inv{\omega C}.
\end{aligned}
\end{equation}
We find the same solutions for either, both leading to
\begin{equation}\label{eqn:RLCbandwidth:240}
B = \Abs{\omega_2 – \omega_1} = \frac{R}{L}.
\end{equation}
This is the (half-power) bandwidth for the RLC circuit. We may now re-express the transfer functions for the filters in terms of the resonant frequency and bandwidth
\begin{equation}\label{eqn:RLCbandwidth:260}
H(s) = \frac{s}{\omega_0^2 + B s + s^2},
\end{equation}
and see by inspection that \( \omega_0 = 1 \) for our circuit (also seen in the plot) and \( B = 3 \,\textrm{rad/s} \).

resolving merge conflicts due to automated C to C++ comment changes

November 17, 2014 C/C++ development and debugging. , , , ,

I was faced with hundreds of merge conflicts that had the following diff3 -m conflict structure:


<<<<<<< file.C.mine
   /* Allocate memory for ProcNamePattern and memset to blank */
   /* ProcNamePattern is used as an intermediate upper case string to capture the procedure name*/
   /* Allocate space for 128 byte schema, 128 byte procedure name */
   rc = BAR(0,
            len+SCHEMA_IDENT+1,
            MEM_DEFAULT,
            &ProcNamePattern);
||||||| file.C.orig
   /* Allocate memory for ProcNamePattern and memset to blank */
   /* ProcNamePattern is used as an intermediate upper case string to capture the procedure name*/
   /* Allocate space for 128 byte schema, 128 byte procedure name */
   rc = FOO(0,
            len+SCHEMA_IDENT+1,
            (void **) &ProcNamePattern);
=======
   // Allocate memory for ProcNamePattern and memset to blank
   // ProcNamePattern is used as an intermediate upper case string to capture the procedure name
   // Allocate space for 128 byte schema, 128 byte procedure name
   rc = FOO(0,
            len+SCHEMA_IDENT+1,
            (void **) &ProcNamePattern);
>>>>>>> file.C.new
   if (rc  )
   {


I’d run a clang based source editing tool that changed FOO to BAR, added a parameter, and removed a cast. Other maintainers of the code had run a tool, or perhaps an editor macro that changed most (but not all) of the C style /* … */ comments into C++ single line comments // …

Those pairs of changes were unfortunately close enough to generate a diff3 -m conflict.

I can run my clang editing tool again (and will), but need to get the source compile-able first, so was faced with either tossing and regenerating my changes, or resolving the conflicts. Basically I needed to filter these comments in the same fashion, and then accept all of my changes, provided there were no other changes in the .orig -> .new stream.

Here’s a little perl filter I wrote for this task:

#!/usr/bin/perl -n

# a script to replace single line /* */ comments with C++ // comments in a restricted fashion.
#
# - doesn't touch comments of the form:
#                                         /* ... */ ... /* ...
#                                         ^^            ^^
# - doesn't touch comments with leading non-whitespace or trailing non-whitespace
#
# This is used to filter new/old/mine triplets in merges to deal with automated replacements of this sort.

chomp ;

if ( ! m,/\*.*/\*, )
{
   s,
^(\s*)   # restrict replacement to comments that start only after beginning of line and whitespace
/\*      # start of comment
\s*      # opt spaces
(.*)     # payload
\s*      # opt spaces
\*/      # end of comment
\s*$     # opt spaces and end of line
,$1// $2,x ;
}

#s,/\* *(.*)(?=\*/ *$)\*/ *$,// $1, ;

print "$_\n" ;

This consumes stdin, and spits out stdout, making the automated change that had been applied to the code. I didn’t want it to do anything with comments of any of the forms:

  • [non-whitespace] /* … */
  • /* … */ … non-whitespace
  • /* … */ … /* … */

Since the comment filtering that’s now in the current version of the files didn’t do this, and I didn’t want to introduce more conflicts due to spacing changes.

With this filter run on all the .mine, .orig, .new versions I was able to rerun

diff3 -m file.mine file.orig file.new

and have only a few actual conflicts to deal with. Most of those were also due to space change and in some cases comment removal.

A lot of this trouble stems from the fact that our product has no coding standards for layout (or very little, or ones that are component specific). I maintain our coding standards for correctness, but when I was given these standards as fairly green developer I didn’t have the guts to take on the role of coding standards dictator, and impose style guidelines on developers very much my senior.

Without style guidelines, a lot of these sorts of merge conflicts could be avoided or minimized significantly if we would only make automated changes with tools that everybody could (or must) run. That would allow conflict filtering of those sort to be done automatically, without having to write ad-hoc tools to “re-play” the automated change in a subset of the merge contributors.

My use of a clang rewriter flies in the face of this ideal conflict avoidance strategy since our build environment is not currently tooled up for our development to do so. However, in this case, being able to do robust automated maintenance ill hopefully be worth the conflicts that this itself will inject.