БИХ-фильтры 2-го порядка |
Предыдущая Содержание Следующая |
|
Код/** * БИХ-фильтры 2-го порядка * расчет взят с http://model.exponenta.ru/audio_eq.html */ public class IIR { public static final byte OFF = 0; public static final byte LOWPASS = 1; public static final byte HIGHPASS = 2; public static final byte RESONANCE = 3; public static final byte BANDPASS1 = 4; public static final byte BANDPASS2 = 5; public static final byte REJECT = 6; public static final byte LOWRES = 8; public static final byte HIGHRES = 7; // private int m_sampleRate; private byte m_type; private int m_frequency; private double m_Q; private int m_dBgain; // private double B0, B1, B2, A1, A2, x2, x1, y2, y1; // public IIR(int sampleRate) { m_sampleRate = sampleRate; reset(); } public void reset() {// выключение фильтра и обнуление истории B0 = 1.0; B1 = B2 = A1 = A2 = x2 = x1 = y2 = y1 = 0.0; m_type = IIR.OFF; m_frequency = -1; m_Q = -1; m_dBgain = 0; } public byte getType() { return m_type; } public int getFrequency() { return m_frequency; } public double getQ() { return m_Q; } public int getGain() { return m_dBgain; } public IIR getClone() {// клонирование фильтра вместе с состоянием IIR flt = new IIR( m_sampleRate ); flt.m_type = this.m_type; flt.m_frequency = this.m_frequency; flt.m_Q = this.m_Q; flt.m_dBgain = this.m_dBgain; // flt.B0 = this.B0; flt.B1 = this.B1; flt.B2 = this.B2; flt.A1 = this.A1; flt.A2 = this.A2; flt.x2 = this.x2; flt.x1 = this.x1; flt.y2 = this.y2; flt.y1 = this.y1; return flt; } public static void copy(IIR src, IIR dst) {// копирование параметров фильтра вместе с состоянием dst.m_sampleRate = src.m_sampleRate; dst.m_type = src.m_type; dst.m_frequency = src.m_frequency; dst.m_Q = src.m_Q; dst.m_dBgain = src.m_dBgain; // dst.B0 = src.B0; dst.B1 = src.B1; dst.B2 = src.B2; dst.A1 = src.A1; dst.A2 = src.A2; dst.x2 = src.x2; dst.x1 = src.x1; dst.y2 = src.y2; dst.y1 = src.y1; } public static void copyState(IIR src, IIR dst) { dst.x2 = src.x2; dst.x1 = src.x1; dst.y2 = src.y2; dst.y1 = src.y1; } public void reinit(byte type, int frequency, double Q, int dBgain) {// перестройка фильтра, -1 (-128 для dBgain) означает, что параметр не меняется init( type < 0 ? m_type : type, frequency < 0 ? m_frequency : frequency, Q < 0 ? m_Q : Q, dBgain < -127 ? m_dBgain : dBgain ); } public void init(byte type, int frequency, double Q, int dBgain) {// инициализация, расчет параметров m_type = type; m_frequency = frequency; m_Q = Q; m_dBgain = dBgain; double omega = 2.0 * Math.PI * (double)frequency / (double)m_sampleRate; double cos = Math.cos( omega ); double A = Math.sqrt( Math.pow( 10.0, dBgain / 20.0 ) ); double alpha = Math.sin( omega ) / ( 2.0 * Q ); //если задана полоса, то другая формула: //alpha = Math.sin( omega ) * Math.sinh( ln(2)/2 * bandWidth * omega / Math.sin( omega ) ); double beta = Math.sqrt( A ) / Q; //если задан наклон горки, то другая формула: //beta = sqrt(A)*sqrt[ (A + 1/A)*(1/S - 1) + 2 ] //beta = sqrt[ (A^2 + 1)/S - (A-1)^2 ] double A0 = 1.0 + alpha; switch( type ) { default: case OFF: B0 = 1.0; B1 = B2 = A1 = A2 = 0.0; break; case LOWPASS: B1 = ( 1.0 - cos ) / A0; B0 = B1 / 2.0; B2 = B0; A1 = -2.0 * cos / A0; A2 = ( 1 - alpha ) / A0; break; case HIGHPASS: B1 = -( 1.0 + cos ) / A0; B0 = -B1 / 2.0; B2 = B0; A1 = -2.0 * cos / A0; A2 = ( 1.0 - alpha ) / A0; break; case RESONANCE: A0 = 1.0 + alpha / A; B0 = ( 1.0 + alpha * A ) / A0; B1 = -2.0 * cos / A0; B2 = ( 1.0 - alpha * A ) / A0; A1 = B1; A2 = ( 1.0 - alpha / A ) / A0; break; case BANDPASS1://max A = Q B0 = Q * alpha / A0; B1 = 0.0; B2 = -B0; A1 = -2.0 * cos / A0; A2 = ( 1.0 - alpha ) / A0; break; case BANDPASS2:// max A = 0 dB B0 = alpha / A0; B1 = 0.0; B2 = -B0; A1 = -2.0 * cos / A0; A2 = ( 1.0 - alpha ) / A0; break; case REJECT: B0 = 1.0 / A0; B1 = -2 * cos / A0; B2 = B0; A1 = B1; A2 = ( 1 - alpha ) / A0; break; case LOWRES: { double ap = A + 1.0; double am = A - 1.0; double amcos = am * cos; double apcos = ap * cos; double bsin = beta * Math.sin( omega ); A0 = ap + amcos + bsin; B0 = A * ( ap - amcos + bsin ) / A0; B1 = 2.0 * A * ( am - apcos ) / A0; B2 = A * ( ap - amcos - bsin ) / A0; A1 = -2.0 * ( am + apcos ) / A0; A2 = ( ap + amcos - bsin ) / A0; break; } case HIGHRES: { double ap = A + 1.0; double am = A - 1.0; double amcos = am * cos; double apcos = ap * cos; double bsin = beta * Math.sin( omega ); A0 = ap - amcos + bsin; B0 = A * ( ap + amcos + bsin ) / A0; B1 = -2.0 * A * ( am + apcos ) / A0; B2 = A * ( ap + amcos - bsin ) / A0; A1 = 2.0 * ( am - apcos ) / A0; A2 = ( ap - amcos - bsin ) / A0; break; } } } public double proc(double sample) {// расчет отклика для каскадного включения без усечения точности double y = B0 * sample + B1 * x1 + B2 * x2 - A1 * y1 - A2 * y2; x2 = x1; x1 = sample; y2 = y1; y1 = y; return y; } public int proc(int sample) {// расчет отклика double y = proc( (double)sample ); return (int)(y > 0 ? y + 0.5 : y - 0.5); } } |
Предыдущая Содержание Следующая |