1. Overview
Since every periodic waveform is a sum of sinusoids, sinusoidal waveforms can be “extracted” from periodic signals. Below, we show how to
-
Generate a square wave from a sum of sinusoids
-
Design an active second-order low-pass filter
-
Use the filter to synthesize a (near) sinusoidal waveform from a square wave by attenuating all but one spectral component
2. Square Wave
Any periodic function can be represented as a sum of sinusoids. In Figure 1, the top panel shows two sinusoids. The bottom panel shows the result of adding them up. While not perfect, the resulting trace has a resemblance to a square-wave.
Increasing the number of sinusoids improves the approximation. Figure 2 shows the result of summing six sinusoids.
3. Low-Pass Filter
Frequency response:
with corner frequency \(\omega_o = 2\pi f_c\). The variable \(s\) denotes complex frequency, \(s = j \omega\) and \(\omega = 2\pi f\).
Design objective:
Gain G |
0.15 |
Cutoff frequency fc |
1.0 kHz |
Quality factor Q |
0.9 |
Circuit parameters as calculated and rounded to “standard” (readily available) component values:
Parameter | calculated | rounded |
---|---|---|
R1 |
154 kΩ |
150 kΩ |
R2 |
23 kΩ |
22 kΩ |
R3 |
50 kΩ |
47 kΩ |
C1 |
10.0 nF |
10 nF |
C2 |
2.2 nF |
2.2 nF |
Gain G |
0.15 |
0.15 |
Cutoff frequency fc |
1.00 kHz |
1.06 kHz |
Quality factor Q |
0.90 |
0.90 |
Bode plot[1]:
from scipy import signal
# Response with actual component values
wo = 2*pi*fc
num = [1]
den = [1/wo**2, 1/Q/wo, 1]
tf = signal.TransferFunction(num,den)
w = 2*pi*logspace(2, 4, num=100)
w, mag, _ = tf.bode(w)
semilogx(w/2/pi, mag)
ylabel("Magnitude [dB]")
xlabel("Frequency [Hz]")
4. Time Domain Response
Figure 5 shows the simulated filter response for square wave inputs at different frequencies. For \(f\ll f_c\) the output resembles the input with some overshoot due to the Q of the filter. As f approaches fc, the waveform gets increasingly distorted and delayed. At f = fc, the response starts resembling a sinusoid. Higher frequency inputs yield high quality sinusoids, with now very noticeable attenuation and phase shift.
Code for simulation:
# 3 periods of 1kHz square wave sampled at 100kHz
t, v = square_wave(1000, 1e5, 3)
# time domain response
t, y, state = tf.output(v, t)
plot(t, y)