Cleanup fir filter design code. Removed Beamforming reference i test_fft.py
This commit is contained in:
parent
ccda090266
commit
53a60877b4
3
.gitignore
vendored
3
.gitignore
vendored
@ -16,4 +16,5 @@ test/test_fft
|
|||||||
test/test_math
|
test/test_math
|
||||||
test/test_workers
|
test/test_workers
|
||||||
doc
|
doc
|
||||||
|
LASP.egg-info
|
||||||
|
lasp_octave_fir.*
|
||||||
|
@ -16,7 +16,8 @@ add_library(lasp_lib
|
|||||||
lasp_mq.c
|
lasp_mq.c
|
||||||
lasp_worker.c
|
lasp_worker.c
|
||||||
lasp_dfifo.c
|
lasp_dfifo.c
|
||||||
lasp_filterbank.c
|
# lasp_filterbank.c
|
||||||
|
lasp_octave_fir.c
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
65
lasp/fir_design/fir_design.py
Normal file
65
lasp/fir_design/fir_design.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""!
|
||||||
|
Author: J.A. de Jong - ASCEE
|
||||||
|
|
||||||
|
Description: Designs octave band FIR filters from 16Hz to 16 kHz for a sampling
|
||||||
|
frequency of 48 kHz.
|
||||||
|
"""
|
||||||
|
#from asceefigs.plot import Bode, close, Figure
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
from scipy.signal import freqz, hann
|
||||||
|
from matplotlib.pyplot import figure, close
|
||||||
|
|
||||||
|
def freqResponse(fir_coefs, freq, fs):
|
||||||
|
"""!
|
||||||
|
Computes the frequency response of the filter defined with filter_coefs
|
||||||
|
"""
|
||||||
|
Omg = 2*np.pi*freq/fs
|
||||||
|
|
||||||
|
w, H = freqz(fir_coefs,worN = Omg)
|
||||||
|
return H
|
||||||
|
|
||||||
|
def bandpass_fir_design(L,fs,fl,fu, window = hann):
|
||||||
|
"""
|
||||||
|
Construct a bandpass filter
|
||||||
|
"""
|
||||||
|
assert fs/2 > fu, "Nyquist frequency needs to be higher than upper cut-off"
|
||||||
|
assert fu > fl, "Cut-off needs to be lower than Nyquist freq"
|
||||||
|
|
||||||
|
Omg2 = 2*np.pi*fu/fs
|
||||||
|
Omg1 = 2*np.pi*fl/fs
|
||||||
|
|
||||||
|
fir = np.empty(L, dtype=float)
|
||||||
|
|
||||||
|
# First Create ideal band-pass filter
|
||||||
|
fir[L//2] = (Omg2-Omg1)/np.pi
|
||||||
|
|
||||||
|
for n in range(1,L//2):
|
||||||
|
fir[n+L//2] = (np.sin(n*Omg2)-np.sin(n*Omg1))/(n*np.pi)
|
||||||
|
fir[L//2-n] = (np.sin(n*Omg2)-np.sin(n*Omg1))/(n*np.pi)
|
||||||
|
|
||||||
|
win = window(L,True)
|
||||||
|
fir_win = fir*win
|
||||||
|
|
||||||
|
return fir_win
|
||||||
|
|
||||||
|
def lowpass_fir_design(L,fs,fc,window = hann):
|
||||||
|
assert fs/2 > fc, "Nyquist frequency needs to be higher than upper cut-off"
|
||||||
|
|
||||||
|
Omgc = 2*np.pi*fc/fs
|
||||||
|
fir = np.empty(L, dtype=float)
|
||||||
|
|
||||||
|
# First Create ideal band-pass filter
|
||||||
|
fir[L//2] = Omgc/np.pi
|
||||||
|
|
||||||
|
for n in range(1,L//2):
|
||||||
|
fir[n+L//2] = np.sin(n*Omgc)/(n*np.pi)
|
||||||
|
fir[L//2-n] = np.sin(n*Omgc)/(n*np.pi)
|
||||||
|
|
||||||
|
win = window(L,True)
|
||||||
|
fir_win = fir*win
|
||||||
|
|
||||||
|
return fir_win
|
||||||
|
|
180
lasp/fir_design/octave_filter_design_fir.py
Normal file
180
lasp/fir_design/octave_filter_design_fir.py
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""!
|
||||||
|
Author: J.A. de Jong - ASCEE
|
||||||
|
|
||||||
|
Description: Designs FIR octave band FIR filters from 16Hz to 16 kHz for a
|
||||||
|
sampling frequency of 48 kHz.
|
||||||
|
"""
|
||||||
|
import numpy as np
|
||||||
|
from octave_filter_limits import octave_band_limits, G, fr
|
||||||
|
from matplotlib.pyplot import figure, close
|
||||||
|
from fir_design import freqResponse, bandpass_fir_design
|
||||||
|
|
||||||
|
L = 256 # Filter order
|
||||||
|
fs = 48000. # Sampling frequency
|
||||||
|
|
||||||
|
showfig = False
|
||||||
|
#showfig = True
|
||||||
|
maxdec = 3
|
||||||
|
close('all')
|
||||||
|
|
||||||
|
filters = {}
|
||||||
|
decimation = {}
|
||||||
|
b = 1
|
||||||
|
# Text corresponding to the nominal frequency
|
||||||
|
nominals = {4:'16k',
|
||||||
|
3:'8k',
|
||||||
|
2:'4k',
|
||||||
|
1:'2k',
|
||||||
|
0:'1k',
|
||||||
|
-1:'500',
|
||||||
|
-2:'250',
|
||||||
|
-3:'125',
|
||||||
|
-4:'63',
|
||||||
|
-5:'31.5',
|
||||||
|
-6:'16'}
|
||||||
|
|
||||||
|
# Factor with which to multiply the cut-on frequency of the FIR filter
|
||||||
|
cut_fac_l = {
|
||||||
|
4:0.995,
|
||||||
|
3:0.99,
|
||||||
|
2:0.98,
|
||||||
|
1:0.99,
|
||||||
|
0:0.98,
|
||||||
|
-1:0.96,
|
||||||
|
-2:.99,
|
||||||
|
-3:0.98,
|
||||||
|
-4:0.96,
|
||||||
|
-5:0.98,
|
||||||
|
-6:0.96
|
||||||
|
}
|
||||||
|
|
||||||
|
# Factor with which to multiply the cut-off frequency of the FIR filter
|
||||||
|
cut_fac_u = {
|
||||||
|
4:1.004,
|
||||||
|
3:1.006,
|
||||||
|
2:1.01,
|
||||||
|
1:1.006,
|
||||||
|
0:1.01,
|
||||||
|
-1:1.02,
|
||||||
|
-2:1.006,
|
||||||
|
-3:1.01,
|
||||||
|
-4:1.02,
|
||||||
|
-5:1.01,
|
||||||
|
-6:1.02
|
||||||
|
}
|
||||||
|
|
||||||
|
# Required decimation for each filter
|
||||||
|
decimation = {
|
||||||
|
4:[1],
|
||||||
|
3:[1],
|
||||||
|
2:[1],
|
||||||
|
1:[4],
|
||||||
|
0:[4],
|
||||||
|
-1:[4],
|
||||||
|
-2:[4,8],
|
||||||
|
-3:[4,8],
|
||||||
|
-4:[4,8],
|
||||||
|
-5:[4,8,4],
|
||||||
|
-6:[4,8,4]
|
||||||
|
}
|
||||||
|
|
||||||
|
# Generate the header file
|
||||||
|
with open('../c/lasp_octave_fir.h','w') as hfile:
|
||||||
|
hfile.write("""// lasp_octave_fir.h
|
||||||
|
//
|
||||||
|
// Author: J.A. de Jong - ASCEE
|
||||||
|
//
|
||||||
|
// Description: This is file is automatically generated from the
|
||||||
|
// octave_filter_design.py Python file.
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
#pragma once
|
||||||
|
#ifndef LASP_OCTAVE_FIR_H
|
||||||
|
#define LASP_OCTAVE_FIR_H
|
||||||
|
#include "lasp_types.h"
|
||||||
|
|
||||||
|
#define MAXDEC (%i) /// Size of the decimation factor array
|
||||||
|
#define OCTAVE_FIR_LEN (%i) /// Filter length
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char* nominal; /// Pointer to the nominal frequency text
|
||||||
|
int x; /// 1000*G^x is the exact midband frequency, where G = 10^(3/10)
|
||||||
|
int decimation_fac[MAXDEC]; // Array with decimation factors that need to be
|
||||||
|
// applied prior to filtering
|
||||||
|
d h[OCTAVE_FIR_LEN];
|
||||||
|
} OctaveFIR;
|
||||||
|
|
||||||
|
extern __thread OctaveFIR OctaveFIRs[%i];
|
||||||
|
|
||||||
|
#endif // LASP_OCTAVE_FIR_H
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
""" %(maxdec,L,len(decimation)))
|
||||||
|
|
||||||
|
# Generate the source code file
|
||||||
|
with open('../c/lasp_octave_fir.c','w') as cfile:
|
||||||
|
cfile.write("""// octave_fir.c
|
||||||
|
//
|
||||||
|
// Author: J.A. de Jong - ASCEE
|
||||||
|
//
|
||||||
|
// Description:
|
||||||
|
// This is an automatically generated file containing filter coefficients
|
||||||
|
// for octave filter banks.
|
||||||
|
//////////////////////////////////////////////////////////////////////
|
||||||
|
#include "lasp_octave_fir.h"
|
||||||
|
|
||||||
|
__thread OctaveFIR OctaveFIRs[%i] = {
|
||||||
|
""" %(len(decimation)))
|
||||||
|
struct = ''
|
||||||
|
for x in range(4,-7,-1):
|
||||||
|
|
||||||
|
if showfig:
|
||||||
|
fig = figure()
|
||||||
|
ax = fig.add_subplot(111)
|
||||||
|
|
||||||
|
dec = decimation[x]
|
||||||
|
d = np.prod(dec)
|
||||||
|
|
||||||
|
struct += '\n {"%s",%i, {' %(nominals[x],x)
|
||||||
|
for i in range(maxdec):
|
||||||
|
try:
|
||||||
|
struct += "%i," % dec[i]
|
||||||
|
except:
|
||||||
|
struct += "0,"
|
||||||
|
struct = struct[:-1] # Strip off last,
|
||||||
|
struct += '},'
|
||||||
|
|
||||||
|
fd = fs/d
|
||||||
|
|
||||||
|
# Exact midband frequency
|
||||||
|
fm = G**(x)*fr
|
||||||
|
|
||||||
|
# Cut-on frequency of the filter
|
||||||
|
f1 = fm*G**(-1/(2*b))*cut_fac_l[x]
|
||||||
|
# Cut-off frequency of the filter
|
||||||
|
f2 = fm*G**(1/(2*b))*cut_fac_u[x]
|
||||||
|
|
||||||
|
fir = bandpass_fir_design(L,fd,f1,f2)
|
||||||
|
|
||||||
|
struct += "{ "
|
||||||
|
for i in fir:
|
||||||
|
struct += "%0.16e," %i
|
||||||
|
struct = struct[:-1] + " }},"
|
||||||
|
|
||||||
|
freq = np.logspace(np.log10(f1/3),np.log10(f2*3),1000)
|
||||||
|
H = freqResponse(fir,freq,fd)
|
||||||
|
if showfig:
|
||||||
|
ax.semilogx(freq,20*np.log10(np.abs(H)))
|
||||||
|
|
||||||
|
freq,ulim,llim = octave_band_limits(x)
|
||||||
|
|
||||||
|
ax.semilogx(freq,ulim)
|
||||||
|
ax.semilogx(freq,llim)
|
||||||
|
ax.set_title('x = %i, fnom = %s' %(x,nominals[x]) )
|
||||||
|
|
||||||
|
ax.set_ylim(-10,1)
|
||||||
|
ax.set_xlim(f1/1.1,f2*1.1)
|
||||||
|
|
||||||
|
struct+="\n};"
|
||||||
|
cfile.write(struct)
|
||||||
|
|
52
lasp/fir_design/octave_filter_limits.py
Normal file
52
lasp/fir_design/octave_filter_limits.py
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
"""!
|
||||||
|
Author: J.A. de Jong - ASCEE
|
||||||
|
|
||||||
|
Description: Limit lines for class 1 octave band filter limits according to
|
||||||
|
the ICS 17.140.50 standard.
|
||||||
|
"""
|
||||||
|
__all__ = ['G','fr','octave_band_limits']
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
# Reference frequency
|
||||||
|
fr = 1000.
|
||||||
|
G = 10**(3/10)
|
||||||
|
|
||||||
|
def octave_band_limits(x):
|
||||||
|
|
||||||
|
# Exact midband frequency
|
||||||
|
fm = G**(x)*fr
|
||||||
|
|
||||||
|
G_power_values_pos = [0,1/8,1/4,3/8,1/2,1/2,1,2,3,4]
|
||||||
|
G_power_values_neg = [-i for i in G_power_values_pos]
|
||||||
|
G_power_values_neg.reverse()
|
||||||
|
G_power_values = G_power_values_neg[:-1] + G_power_values_pos
|
||||||
|
|
||||||
|
mininf = -1e300
|
||||||
|
|
||||||
|
lower_limits_pos = [-0.3,-0.4,-0.6,-1.3,-5.0,-5.0]+ 4*[mininf]
|
||||||
|
lower_limits_neg = lower_limits_pos[:]
|
||||||
|
lower_limits_neg.reverse()
|
||||||
|
lower_limits = np.asarray(lower_limits_neg[:-1] + lower_limits_pos)
|
||||||
|
|
||||||
|
upper_limits_pos = [0.3]*5 + [-2,-17.5,-42,-61,-70]
|
||||||
|
upper_limits_neg = upper_limits_pos[:]
|
||||||
|
upper_limits_neg.reverse()
|
||||||
|
upper_limits = np.asarray(upper_limits_neg[:-1] + upper_limits_pos)
|
||||||
|
|
||||||
|
freqs = fm*G**np.asarray(G_power_values)
|
||||||
|
|
||||||
|
return freqs,upper_limits,lower_limits
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
|
||||||
|
from asceefigs.plot import close, Figure
|
||||||
|
close('all')
|
||||||
|
freqs,upper_limits,lower_limits = octave_band_limits(0)
|
||||||
|
|
||||||
|
f = Figure()
|
||||||
|
f.semilogx(freqs,lower_limits)
|
||||||
|
f.semilogx(freqs,upper_limits)
|
||||||
|
|
||||||
|
f.ylim(-80,1)
|
@ -6,7 +6,7 @@ Created on Mon Jan 15 19:45:33 2018
|
|||||||
@author: anne
|
@author: anne
|
||||||
"""
|
"""
|
||||||
import numpy as np
|
import numpy as np
|
||||||
from beamforming import Fft
|
from lasp import Fft
|
||||||
|
|
||||||
nfft=9
|
nfft=9
|
||||||
print('nfft:',nfft)
|
print('nfft:',nfft)
|
||||||
|
Loading…
Reference in New Issue
Block a user