Main Content

HDL Tone Control Filter Bank

This example illustrates how to generate HDL code for bank of 24 first-order shelving filters that implement an audio tone control with 1 dB steps from -6 dB to +6 dB for bass and treble.

The filters are analytically designed using a simple formula for a first-order filter with one pole and one zero on the real axis.

A filter bank is designed since changing the filter coefficients on-the-fly can lead to transients in the audio (clicks and pops) as the boost/cut control is moved. With a bank of filters running continuously, the appropriate filter is selected from the bank of filters when the output is near any zero crossing to avoid these transients.

Set up the Parameters

Use the CD sampling rate of 44.1 kHz with bass and treble corners at 100 Hz and 1600Hz.

Fs  = 44100;                            % all in Hz
Fcb =   100;
Fct =  1600;

Define the Tangent Frequency Mapping Parameters

Map the corner frequencies by the tangent to move from the analog to the digital domain. Then, define the range of cut and boost to be applied, choosing a 12 dB total range in 1 dB steps. Convert decibels to linear gain and separate the boost and cut vectors.

basstan   = tan(pi*Fcb/Fs);
trebletan = tan(pi*Fct/Fs);

dbrange  = [-6:-1, +1:+6];              % -6 dB to +6 dB 
linrange = 10.^(dbrange/20);
boost = linrange(linrange>1);
cut   = linrange(linrange<=1);
Nfilters = 2 * length(dbrange);         % 2X for bass and treble

Design the Filter Bank

Complete the bilinear transform on the poles, then compute the zeros of the filters based on the desired boost or cut. Since boost and cut are vectors, we can design all the filters at the same time using vector arithmetic. Note that a1 is always one in these filters.

a2_bass_boost    = (basstan - 1) / (basstan + 1);
b1_bass_boost   = 1 + ((1 + a2_bass_boost) .* (boost - 1)) / 2;
b2_bass_boost   = a2_bass_boost + ...
                  ((1 + a2_bass_boost) .* (boost - 1)) / 2;

a2_bass_cut      = (basstan - cut) / (basstan + cut);
b1_bass_cut     = 1 + ((1 + a2_bass_cut) .* (cut - 1)) / 2;
b2_bass_cut     = a2_bass_cut + ((1 + a2_bass_cut) .* (cut - 1)) / 2;

a2_treble_boost  = (trebletan - 1) / (trebletan + 1); 
b1_treble_boost   = 1 + ((1 - a2_treble_boost) .* (boost - 1)) / 2;
b2_treble_boost   = a2_treble_boost + ...
                    ((a2_treble_boost - 1) .* (boost - 1)) / 2;

a2_treble_cut      = (cut .* trebletan - 1) / (cut .* trebletan + 1);
b1_treble_cut     = 1 + ((1 - a2_treble_cut) .* (cut - 1)) / 2;
b2_treble_cut     = a2_treble_cut + ...
                    ((a2_treble_cut - 1) .* (cut - 1)) / 2;

Build the Filter Bank

Build the numerator and denominator arrays for the entire filter bank. Then build a cell array of filters in {b,a,b,a,...} form for fvtool. Preallocate the cell array for speed.

filterbank = cell(1, 2*Nfilters);     % 2X for numerator and denominator
% Duplicate a2's into vectors
a2_bass_boost   = repmat(a2_bass_boost,   1, length(boost));
a2_bass_cut     = repmat(a2_bass_cut,     1, length(cut));
a2_treble_boost = repmat(a2_treble_boost, 1, length(boost));
a2_treble_cut   = repmat(a2_treble_cut,   1, length(cut));

filterbank_num = [b1_bass_cut, b1_bass_boost, b1_treble_cut, b1_treble_boost ; ...
                  b2_bass_cut, b2_bass_boost, b2_treble_cut, b2_treble_boost ]';
% a1 is always one
filterbank_den = [ones(1, Nfilters); ...
                  a2_bass_cut, a2_bass_boost, a2_treble_cut, a2_treble_boost]';

filterbank(1:2:end) = num2cell(filterbank_num, 2);
filterbank(2:2:end) = num2cell(filterbank_den, 2);

Check the Response of the Filter Bank

Use fvtool in log frequency mode to see the audio band more clearly. Also set the sampling frequency.

fvtool(filterbank{:}, 'FrequencyScale', 'log', 'Fs', Fs);

Figure Figure 1: Magnitude Response (dB) contains an axes object. The axes object with title Magnitude Response (dB), xlabel Frequency (kHz), ylabel Magnitude (dB) contains 24 objects of type line.

Create the Quantized Filter Bank

Create a quantized filter for each double-precision filter designed above. Assume CD-quality input of 16 bits and an output word length of 18 bits to allow for the +6 dB gain with some headroom.

quantizedfilterbank = cell(1, Nfilters);
for n = 1:Nfilters
  quantizedfilterbank{n} = dsp.BiquadFilter('Structure','Direct Form I');
  quantizedfilterbank{n}.SOSMatrix = [filterbank_num(n,:),0,...
                                      filterbank_den(n,:),0];

  quantizedfilterbank{n}.NumeratorCoefficientsDataType         = 'Custom';
  quantizedfilterbank{n}.CustomNumeratorCoefficientsDataType   = numerictype([],16);
  quantizedfilterbank{n}.CustomDenominatorCoefficientsDataType = numerictype([],16);
  quantizedfilterbank{n}.CustomScaleValuesDataType             = numerictype([],16);
  
  quantizedfilterbank{n}.OutputDataType       = 'Custom';
  quantizedfilterbank{n}.CustomOutputDataType = numerictype([],18,15);
  
  quantizedfilterbank{n}.SectionOutputDataType       = 'Custom';
  quantizedfilterbank{n}.CustomSectionOutputDataType = numerictype([],18,15);
  quantizedfilterbank{n}.NumeratorProductDataType    = 'Full precision';
  quantizedfilterbank{n}.DenominatorProductDataType  = 'Full precision';
  
  quantizedfilterbank{n}.NumeratorAccumulatorDataType         = 'Custom';
  quantizedfilterbank{n}.CustomNumeratorAccumulatorDataType   = numerictype([],34,30);
  quantizedfilterbank{n}.DenominatorAccumulatorDataType       = 'Custom';
  quantizedfilterbank{n}.CustomDenominatorAccumulatorDataType = numerictype([],34,29);
  
  quantizedfilterbank{n}.RoundingMethod  = 'Floor';
  quantizedfilterbank{n}.OverflowAction  = 'Wrap';
end

Check the Response of the Quantized Filter Bank

Check the quantized filter bank using fvtool again in log frequency mode with the sampling rate set.

fvtool(quantizedfilterbank{:}, 'FrequencyScale', 'log', 'Fs', Fs,'Arithmetic','fixed');

Figure Figure 2: Magnitude Response (dB) contains an axes object. The axes object with title Magnitude Response (dB), xlabel Frequency (kHz), ylabel Magnitude (dB) contains 48 objects of type line. These objects represent Filter #1: Quantized, Filter #1: Reference, Filter #2: Quantized, Filter #2: Reference, Filter #3: Quantized, Filter #3: Reference, Filter #4: Quantized, Filter #4: Reference, Filter #5: Quantized, Filter #5: Reference, Filter #6: Quantized, Filter #6: Reference, Filter #7: Quantized, Filter #7: Reference, Filter #8: Quantized, Filter #8: Reference, Filter #9: Quantized, Filter #9: Reference, Filter #10: Quantized, Filter #10: Reference, Filter #11: Quantized, Filter #11: Reference, Filter #12: Quantized, Filter #12: Reference, Filter #13: Quantized, Filter #13: Reference, Filter #14: Quantized, Filter #14: Reference, Filter #15: Quantized, Filter #15: Reference, Filter #16: Quantized, Filter #16: Reference, Filter #17: Quantized, Filter #17: Reference, Filter #18: Quantized, Filter #18: Reference, Filter #19: Quantized, Filter #19: Reference, Filter #20: Quantized, Filter #20: Reference, Filter #21: Quantized, Filter #21: Reference, Filter #22: Quantized, Filter #22: Reference, Filter #23: Quantized, Filter #23: Reference, Filter #24: Quantized, Filter #24: Reference.

Generate HDL for the Filter Bank and Test Benches

Generate HDL for each of the 24 first-order filters and test benches to check each design. The target language here is Verilog.

Use the canonic sign-digit (CSD) techniques to avoid using multipliers in the design. Specify this with the 'CoeffMultipliers', 'CSD' property-value pair. Since the results of using this optimization are not always numerically identical to regular multiplication that results in overflows, set the test bench 'ErrorMargin' property to 1 bit of allowable error.

Create a custom stimulus to illustrate the gain of filters by generating one-half cycle of a 20 Hz tone and 250 cycles of a 10 kHz tone. Use the low frequency tone for the bass boost/cut filters and the high frequency tone for the treble boost/cut filters.

Create a temporary work directory.

To generate VHDL code instead, change the property 'TargetLanguage', from 'Verilog' to 'VHDL'.

bassuserstim = sin(2*pi*20/Fs*(0:Fs/40));
trebuserstim = sin(2*pi*10000/Fs*(0:Fs/40));
workingdir   = tempname;

for n = 1:Nfilters/2
  generatehdl(quantizedfilterbank{n},...
              'Name', ['tonecontrol', num2str(n)],...
              'TargetDirectory', workingdir,...
              'InputDataType', numerictype(1,16,15),...
              'TargetLanguage', 'Verilog',...
              'CoeffMultipliers','CSD', ...
              'GenerateHDLTestbench','on', ...
              'TestBenchUserStimulus', bassuserstim, ...
              'ErrorMargin', 1);           
end
### Starting Verilog code generation process for filter: tonecontrol1
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol1.v
### Starting generation of tonecontrol1 Verilog module
### Starting generation of tonecontrol1 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol1
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol1_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol2
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol2.v
### Starting generation of tonecontrol2 Verilog module
### Starting generation of tonecontrol2 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol2
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol2_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol3
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol3.v
### Starting generation of tonecontrol3 Verilog module
### Starting generation of tonecontrol3 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol3
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol3_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol4
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol4.v
### Starting generation of tonecontrol4 Verilog module
### Starting generation of tonecontrol4 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol4
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol4_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol5
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol5.v
### Starting generation of tonecontrol5 Verilog module
### Starting generation of tonecontrol5 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol5
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol5_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol6
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol6.v
### Starting generation of tonecontrol6 Verilog module
### Starting generation of tonecontrol6 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol6
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol6_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol7
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol7.v
### Starting generation of tonecontrol7 Verilog module
### Starting generation of tonecontrol7 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol7
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol7_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol8
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol8.v
### Starting generation of tonecontrol8 Verilog module
### Starting generation of tonecontrol8 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol8
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol8_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol9
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol9.v
### Starting generation of tonecontrol9 Verilog module
### Starting generation of tonecontrol9 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol9
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol9_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol10
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol10.v
### Starting generation of tonecontrol10 Verilog module
### Starting generation of tonecontrol10 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol10
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol10_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol11
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol11.v
### Starting generation of tonecontrol11 Verilog module
### Starting generation of tonecontrol11 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol11
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol11_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol12
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol12.v
### Starting generation of tonecontrol12 Verilog module
### Starting generation of tonecontrol12 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol12
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol12_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
for n = Nfilters/2+1:Nfilters
  generatehdl(quantizedfilterbank{n},...
              'Name', ['tonecontrol', num2str(n)],...
              'TargetDirectory', workingdir,...
              'InputDataType', numerictype(1,16,15),...
              'TargetLanguage', 'Verilog',...
              'CoeffMultipliers','CSD', ...
              'GenerateHDLTestbench','on', ...
              'TestBenchUserStimulus', bassuserstim, ...
              'ErrorMargin', 1);
end
### Starting Verilog code generation process for filter: tonecontrol13
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol13.v
### Starting generation of tonecontrol13 Verilog module
### Starting generation of tonecontrol13 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol13
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol13_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol14
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol14.v
### Starting generation of tonecontrol14 Verilog module
### Starting generation of tonecontrol14 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol14
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol14_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol15
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol15.v
### Starting generation of tonecontrol15 Verilog module
### Starting generation of tonecontrol15 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol15
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol15_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol16
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol16.v
### Starting generation of tonecontrol16 Verilog module
### Starting generation of tonecontrol16 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol16
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol16_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol17
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol17.v
### Starting generation of tonecontrol17 Verilog module
### Starting generation of tonecontrol17 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol17
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol17_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol18
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol18.v
### Starting generation of tonecontrol18 Verilog module
### Starting generation of tonecontrol18 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol18
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol18_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol19
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol19.v
### Starting generation of tonecontrol19 Verilog module
### Starting generation of tonecontrol19 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol19
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol19_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol20
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol20.v
### Starting generation of tonecontrol20 Verilog module
### Starting generation of tonecontrol20 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol20
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol20_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol21
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol21.v
### Starting generation of tonecontrol21 Verilog module
### Starting generation of tonecontrol21 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol21
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol21_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol22
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol22.v
### Starting generation of tonecontrol22 Verilog module
### Starting generation of tonecontrol22 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol22
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol22_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol23
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol23.v
### Starting generation of tonecontrol23 Verilog module
### Starting generation of tonecontrol23 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol23
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol23_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.
### Starting Verilog code generation process for filter: tonecontrol24
### Generating: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol24.v
### Starting generation of tonecontrol24 Verilog module
### Starting generation of tonecontrol24 Verilog module body
### First-order section, # 1
### Successful completion of Verilog code generation process for filter: tonecontrol24
### HDL latency is 2 samples
### Starting generation of VERILOG Test Bench.
### Generating input stimulus
### Done generating input stimulus; length 1103 samples.
### Generating Test bench: /tmp/Bdoc23b_2361005_717342/tpf162eaeb_d4d2_4820_b5dc_478ac6019ea8/tonecontrol24_tb.v
### Creating stimulus vectors ...
### Done generating VERILOG Test Bench.

ModelSim® Simulation Results

The following display shows the ModelSim® HDL simulator running these test benches.

Bass response to the 20 Hz tone:

Treble response to the 10 kHz tone:

Conclusion

You designed a filter bank of double-precision bass and treble boost/cut first order filters directly using the bilinear transform. You then used the filter coefficients to create a bank of quantized filters with CD-quality 16-bit inputs and 18-bit outputs. After checking the response of the quantized filters, you generated Verilog code for each filter in the filter bank along with a Verilog test bench that used a custom input stimulus for the bass and treble filters.

To complete the solution of providing tone controls to an audio system, you can add a cross-fader to the outputs of each section of the filter bank. These cross-faders should take several sample times to switch smoothly from one boost or cut step to the next.

Using a full bank of filters is only one approach to solving this type of problem. Another approach would be to use two filters for each band (bass and treble) with programmable coefficients that can be changed under software control. One of the two filters would be the current setting, while the other would be the next setting. As you adjusted the tone controls, the software would ping-pong between the filters exchanging current and next with a simple fader. The trade-off is that the constant coefficient filter bank shown above is uses no multipliers while the seemingly simpler ping-pong scheme requires several multipliers.