Mercurial > hg > ltpda
diff m-toolbox/classes/@pzmodel/pzm2ab.m @ 0:f0afece42f48
Import.
author | Daniele Nicolodi <nicolodi@science.unitn.it> |
---|---|
date | Wed, 23 Nov 2011 19:22:13 +0100 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/m-toolbox/classes/@pzmodel/pzm2ab.m Wed Nov 23 19:22:13 2011 +0100 @@ -0,0 +1,209 @@ +% PZM2AB convert pzmodel to IIR filter coefficients using bilinear transform. +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% DESCRIPTION: PZM2AB convert pzmodel to IIR filter coefficients using bilinear +% transform. +% +% CALL: [a,b] = pzm2ab(pzm, fs) +% +% VERSION: $Id: pzm2ab.m,v 1.10 2009/08/31 17:11:41 ingo Exp $ +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function varargout = pzm2ab(varargin) + + import utils.const.* + + %%% Collect input variable names + in_names = cell(size(varargin)); + for ii = 1:nargin,in_names{ii} = inputname(ii);end + + %%% Collect all AOs and plists + [pzm, pzm_invars, fs] = utils.helper.collect_objects(varargin(:), 'pzmodel', in_names); + + %%% Check inputs + if numel(pzm) ~= 1 + error('### Please use only one PZ-Model.'); + end + if numel(fs) ~= 1 && ~isnumeric(fs) + error('### Please define ''fs''.'); + else + fs = fs{1}; + end + + gain = pzm.gain; + poles = pzm.poles; + zeros = pzm.zeros; + np = numel(poles); + nz = numel(zeros); + + ao = []; + bo = []; + + utils.helper.msg(utils.const.msg.OPROC1, 'converting %s', pzm.name) + + % First we should do complex pole/zero pairs + cpoles = []; + for j=1:np + if poles(j).q > 0.5 + cpoles = [cpoles poles(j)]; + end + end + czeros = []; + for j=1:nz + if zeros(j).q > 0.5 + czeros = [czeros zeros(j)]; + end + end + + czi = 1; + for j=1:length(cpoles) + if czi <= length(czeros) + % we have a pair + p = cpoles(j); + z = czeros(czi); + + [ai,bi] = cpolezero(p.f, p.q, z.f, z.q, fs); + if ~isempty(ao) + [ao,bo] = pzmodel.abcascade(ao,bo,ai,bi); + else + ao = ai; + bo = bi; + end + + % increment zero counter + czi = czi + 1; + end + end + + if length(cpoles) > length(czeros) + % do remaining cpoles + for j=length(czeros)+1:length(cpoles) + utils.helper.msg(msg.OPROC2, 'computing complex pole'); + [ai,bi] = cp2iir(cpoles(j), fs); + if ~isempty(ao) + [ao,bo] = pzmodel.abcascade(ao,bo,ai,bi); + else + ao = ai; + bo = bi; + end + end + else + % do remaining czeros + for j=length(cpoles)+1:length(czeros) + utils.helper.msg(msg.OPROC2, 'computing complex zero'); + [ai,bi] = cz2iir(czeros(j), fs); + if ~isempty(ao) + [ao,bo] = pzmodel.abcascade(ao,bo,ai,bi); + else + ao = ai; + bo = bi; + end + end + end + + % Now do the real poles and zeros + for j=1:np + pole = poles(j); + if isnan(pole.q) || pole.q < 0.5 + utils.helper.msg(msg.OPROC2, 'computing real pole'); + [ai,bi] = rp2iir(pole, fs); + if ~isempty(ao) + [ao,bo] = pzmodel.abcascade(ao,bo,ai,bi); + else + ao = ai; + bo = bi; + end + end + end + + for j=1:nz + zero = zeros(j); + if isnan(zero.q) || zero.q < 0.5 + utils.helper.msg(msg.OPROC2, 'computing real zero'); + [ai,bi] = rz2iir(zero, fs); + if ~isempty(ao) + [ao,bo] = pzmodel.abcascade(ao,bo,ai,bi); + else + ao = ai; + bo = bi; + end + end + end + + ao = ao.*gain; + + varargout{1} = ao; + varargout{2} = bo; +end + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% Local Functions % +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% FUNCTION: cpolezero +% +% DESCRIPTION: Return IIR filter coefficients for a complex pole and +% complex zero designed using the bilinear transform. +% +% CALL: [a,b] = cpolezero(pf, pq, zf, zq, fs) +% +% HISTORY: 18-02-2007 M Hewitson +% Creation. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function [a,b] = cpolezero(pf, pq, zf, zq, fs) + + import utils.const.* + utils.helper.msg(msg.OPROC1, 'computing complex pole/zero pair'); + + wp = pf*2*pi; + wp2 = wp^2; + wz = zf*2*pi; + wz2 = wz^2; + + k = 4*fs*fs + 2*wp*fs/pq + wp2; + + a(1) = (4*fs*fs + 2*wz*fs/zq + wz2)/k; + a(2) = (2*wz2 - 8*fs*fs)/k; + a(3) = (4*fs*fs - 2*wz*fs/zq + wz2)/k; + b(1) = 1; + b(2) = (2*wp2 - 8*fs*fs)/k; + b(3) = (wp2 + 4*fs*fs - 2*wp*fs/pq)/k; + + % normalise dc gain to 1 + g = iirdcgain(a,b); + a = a / g; +end + + +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% +% +% FUNCTION: iirdcgain +% +% DESCRIPTION: Work out the DC gain of an IIR filter given the coefficients. +% +% CALL: g = iirdcgain(a,b) +% +% INPUTS: a - numerator coefficients +% b - denominator coefficients +% +% OUTPUTS g - gain +% +% HISTORY: 03-07-2002 M Hewitson +% Creation. +% +%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + +function g = iirdcgain(a,b) + suma = sum(a); + if(length(b)>1) + sumb = sum(b); + g = suma / sumb; + else + g = suma; + end +end