Filter coefficients from frequency response with invfreqs/invfreqz

11 views (last 30 days)
Hi,
I have a linear time invariant system (spring-mass-damper), the input of the system is a trapezoidal acceleration power spectral density applied to the base of the system, the output is the root mean square of the acceleration of the mass. To evaluate the rms of the output I would like to use lyap, but I can use it only if the input of the system is a white noise.
I want to design a filter that has as input a white noise ( a flat power spectral density) and as output the input of my LTI system: the trapezoidal acceleration power spectral density. I need only the coefficients of the filter so that I can evaluate the space-state form of the filter and of the filter + LTI (needed to use lyap).
I don't understand exactly how to use invfreqs/invfreqz. The magnitude response of the designed filter doesn't match with what I would like to have.
Here's the code:
clear all; close all; clc
%% Defining the trapezoidal APSD
df = 0.1;
f_a = 20; f_b = 100; f_c = 300; f_d = 2000; % freq points
s_l = 3; s_r = -5; % slopes
APSD_m = 1; % flat mid PSD
f_l = f_a:df:f_b; f_m = f_b:df:f_c; f_r = f_c:df:f_d;
APSD_l = APSD_m * (f_l/f_b) .^ (s_l/(10*log10(2))); % left PSD
APSD_r = APSD_m * (f_r/f_c) .^ (s_r/(10*log10(2))); % right PSD
APSD_m = APSD_m * ones(1,length(f_m)); % mid PSD
f_APSD = [f_l,f_m,f_r];
APSD = [APSD_l,APSD_m,APSD_r];
%% Filter invfreqz
desiredResponse = sqrt(APSD); % The magnitude response I would like to have
normalizedFrequency = f_APSD./f_APSD(end) * pi;
[b,a] = invfreqz(desiredResponse,normalizedFrequency,10,13,[],30); % to get filter coefficients
zplane(b,a)
[h,w] = freqz(b,a,length(f_APSD)); % to see the frequency response of the filter
figure()
loglog(f_APSD,APSD,'-k',f_APSD,abs(h).^2,'-g')
legend('Target APSD','Filter Response')

Accepted Answer

Paul
Paul on 16 May 2023
Edited: Paul on 17 May 2023
Assuming that f_APSD is in Hz, the filter, h, below gives a reasonable match to APSD.
df = 0.1;
f_a = 20; f_b = 100; f_c = 300; f_d = 2000; % freq points
s_l = 3; s_r = -5; % slopes
APSD_m = 1; % flat mid PSD
f_l = f_a:df:f_b; f_m = f_b:df:f_c; f_r = f_c:df:f_d;
APSD_l = APSD_m * (f_l/f_b) .^ (s_l/(10*log10(2))); % left PSD
APSD_r = APSD_m * (f_r/f_c) .^ (s_r/(10*log10(2))); % right PSD
APSD_m = APSD_m * ones(1,length(f_m)); % mid PSD
f_APSD = [f_l,f_m,f_r];
APSD = [APSD_l,APSD_m,APSD_r];
%% Filter invfreqz
%{
desiredResponse = sqrt(APSD); % The magnitude response I would like to have
normalizedFrequency = f_APSD./f_APSD(end) * pi;
[b,a] = invfreqz(desiredResponse,normalizedFrequency,10,13,[],30); % to get filter coefficients
zplane(b,a)
[h,w] = freqz(b,a,length(f_APSD)); % to see the frequency response of the filter
figure()
loglog(f_APSD,APSD,'-k',f_APSD,abs(h).^2,'-g')
legend('Target APSD','Filter Response')
%}
g = APSD(1)/(2*pi*f_APSD(1));
h = tf(g*[1 0],1)*tf(1,[1/(2*pi*f_b) 1])*tf(1,[1/(2*pi*f_c) 1])^2;
h = tf(g*[1 0],1)*tf(1,[1/(2*pi*f_c*0.85) 1])^3;
zpk(h)
ans = 6.5822e06 s ----------- (s+1602)^3 Continuous-time zero/pole/gain model.
figure
semilogx(f_APSD,20*log10(APSD),f_APSD,db(squeeze(bode(h,2*pi*f_APSD)))),grid
xlabel('Hz');ylabel('dB')
Not sure how good the match needs to be, or if it's really needed to match sqrt(APSD) as I don't fully understand why this approximation helps to evaluate the RMS of the output in response to some input. If the input and the system are known, shouldn't it be possible to find the RMS of the output from that information alone?
  12 Comments
Paul
Paul on 20 May 2023
Edited: Paul on 21 May 2023
Here is a complete code. It's not the same code that I used in the comment above, but gives a very similar result.
The key piece is to esimate the phase of a SISO system based only on the gain. This code uses the methodology from Relationship of magnitude response to phase response. It seems to work for this problem and simple cases, but I certainly haven't tested it a lot.
Here's an example of estimating the phase from the magnitude for a simple problem.
warning('off'); % turn warnings off to not clutter up the output. Lot's of warnings!
h = tf(1,[1 1]);h = h*tf([1 5],[1 100]);
w = logspace(-2,3,1000);
Hw = squeeze(freqresp(h,w));
w0 = w(1:20:end);
figure
semilogx(w,180/pi*angle(Hw),w0,180/pi*phaseest(@(w) reshape(abs(freqresp(h,w)),size(w)),w0),'o')
xlabel('rad/sec'); ylabel('deg')
Define the desired APSD
df = 0.1;
f_a = 20; f_b = 100; f_c = 300; f_d = 2000; % freq points
s_l = 3; s_r = -5; % slopes
APSD_m = 1; % flat mid PSD
f_l = f_a:df:f_b; f_m = f_b+df:df:f_c; f_r = f_c+df:df:f_d;
APSD_l = APSD_m * (f_l/f_b) .^ (s_l/(10*log10(2))); % left PSD
APSD_r = APSD_m * (f_r/f_c) .^ (s_r/(10*log10(2))); % right PSD
APSD_m = APSD_m * ones(1,length(f_m)); % mid PSD
f_APSD = [f_l,f_m,f_r];
APSD = [APSD_l,APSD_m,APSD_r];
Estimate the phase of the desired pre-filter, which has magnitude equal to the sqrt of the magnitude of APSD.
Extend f_APSD the left to get a better estimate at low frequency.
f0 = [0.1 f_APSD(1:100:end)];
phasesqrtapsd2 = phaseest(@(w) (sqrt(apsdcalc(w/2/pi))),2*pi*f0);
magsqrtapsd2 = sqrt(apsdcalc(f0));
Use invfreqs to estimate the transfer function.
[b2,a2] = invfreqs(magsqrtapsd2.*exp(1j*phasesqrtapsd2),2*pi*f0,2,4,0*f0+1,30);
Convert to zpk form. There is a poles at very high frequency
sqrtapsdsys = zpk(tf(b2,a2))
sqrtapsdsys = 1.3257e20 (s+201.6) (s+2.942) ----------------------------------------- (s+5.274e16) (s+1885) (s+610.3) (s+61.26) Continuous-time zero/pole/gain model.
Eliminate the pole at high frequency. Maybe should use invfreqs to specify third order denominator.
sqrtapsdsys = freqsep(sqrtapsdsys,2000)
sqrtapsdsys = 2513.4 (s+201.6) (s+2.942) ---------------------------- (s+61.26) (s+610.3) (s+1885) Continuous-time zero/pole/gain model.
Compare APSD with the squared magnitude of the filter, over the frequency range of interest.
figure
semilogx( ...
f_APSD, db(APSD), ...
f_APSD, db(abs(freqs(b2,a2,2*pi*f_APSD)).^2), ...
f_APSD, db(abs(squeeze(freqresp(sqrtapsdsys,2*pi*f_APSD))).^2) ...
) ,grid
xlabel('Hz')
legend('APSD','(b2/a2)^2','sqrtapsdsys^2')
Maybe it would be good to adjust the gain on sqrtapsdsys so that the area under APSD and the area under abs(sqrtapsdsys)^2 over the frequency range of interest is the same?
Plant model for testing. Base acceleration is the input, mass acceleration is the output.
wn = 2*pi*200;
zeta = 0.3;
h = tf([2*zeta*wn wn^2],[1 2*zeta*wn wn^2]);
sys = ss(h);
Augment the plant with the pre-filter.
augsys = sys*sqrtapsdsys;
Compute the figure of merit using lyap
W = 1;
X = lyap(augsys.A,augsys.B*W*augsys.B');
V = augsys.C*X*augsys.C.'
V = 1.2081e+03
Compute the figure of merit by direct integration of the product of APSD and abs(sys)^2.
2*integral(@(f) apsdcalc(f).*reshape(abs(freqresp(sys,2*pi*f)).^2,size(f)),0,inf)
ans = 1.2253e+03
warning('on')
function apsd = apsdcalc(f)
% Compute APSD at arbitray frequency. Assumes that APSD rolls off to zero
% using the same equation for f < f_a and f > f_d.
f_a = 20; f_b = 100; f_c = 300; f_d = 2000; % freq points
s_l = 3; s_r = -5; % slopes
APSD_m = 1;
apsd = 0*f + APSD_m;
APSD_m = 1; % flat mid PSD
apsd(abs(f)<=f_b) = APSD_m * (abs(f(abs(f)<=f_b))/f_b) .^ (s_l/(10*log10(2))); % left PSD
apsd(abs(f)>=f_c) = APSD_m * (abs(f(abs(f)>=f_c)/f_c)) .^ (s_r/(10*log10(2))); % right PSD
apsd(apsd <= 1e-10) = 1e-10;
end
function phase = phaseest(mag,w0)
phase = nan*w0;
for ii = 1:numel(w0)
phase(ii) = -myhilbert(@(w) log(mag(w)),w0(ii));
end
end
function hi = myhilbert(f,w0)
x = @(w) f(w)./(w0-w);
% hi = integral(x,-inf,inf);
hi = ( integral(x,-inf,w0-eps) + integral(x,w0+eps,inf) )/pi;
end

Sign in to comment.

More Answers (0)

Products


Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!