Exemplo n.º 1
0
def tune_rom(SSb,
             kv,
             tol,
             gv,
             method='realisation',
             convergence='all',
             Print=False):
    """
    Starting from a balanced DLTI, this function determines the number of states
    N required in a ROM (obtained either through 'residualisation' or
    'truncation' as specified in method - see also librom.modred) to match the
    frequency response of SSb over the frequency array, kv, with absolute
    accuracy tol. gv contains the balanced system Hankel singular value, and is
    used to determine the upper bound for the ROM order N.

    Unless kv does not conver the full Nyquist frequency range, the ROM accuracy
    is not guaranteed to increase monothonically with the number of states. To
    account for this, two criteria can be used to determine the ROM convergence:

        - convergence='all': in this case, the number of ROM states N is chosen
        such that any ROM of order greater than N produces an error smaller than
        tol. To guarantee this the ROM frequency response is computed for all
        N<=Nb, where Nb is the number of balanced states. This method is
        numerically inefficient.

        - convergence='min': atempts to find the minimal number of states to
        achieve the accuracy tol.

    Note:
    - the input state-space model, SSb, must be balanced.
    - the routine in not implemented for numerical efficiency and assumes that
    SSb is small.
    """

    # reference frequency response
    Nb = SSb.A.shape[0]
    Yb = libss.freqresp(SSb, kv, dlti=True)
    if gv is None:
        Nmax = Nb
    else:
        Nmax = min(np.sum(gv > tol) + 1, Nb)

    if convergence == 'all':
        # start from larger size and decrease untill the ROm accuracy is over tol
        Found = False
        N = Nmax
        while not Found:
            SSrom = modred(SSb, N, method)
            Yrom = libss.freqresp(SSrom, kv, dlti=True)
            er = np.max(np.abs(Yrom - Yb))
            if Print:
                print('N=%.3d, er:%.2e (tol=%.2e)' % (N, er, tol))

            if N == Nmax and er > tol:
                warnings.warn(
                    'librom.tune_rom: error %.2e above tolerance %.2e and HSV bound %.2e' \
                    % (er, tol, gv[N - 1]))
            # raise NameError('Hankel singluar values do not '\
            # 				'provide a bound for error! '\
            # 				'The balanced system may not be accurate')
            if er < tol:
                N -= 1
            else:
                N += 1
                Found = True
                SSrom = modred(SSb, N, method)

    elif convergence == 'min':
        Found = False
        N = 1
        while not Found:
            SSrom = modred(SSb, N, method)
            Yrom = libss.freqresp(SSrom, kv, dlti=True)
            er = np.max(np.abs(Yrom - Yb))
            if Print:
                print('N=%.3d, er:%.2e (tol=%.2e)' % (N, er, tol))
            if er < tol:
                Found = True

            else:
                N += 1

    else:
        raise NameError("'convergence' method not implemented")

    return SSrom
Exemplo n.º 2
0
# Frequency analysis
ds = 2. / M
fs = 1. / ds
fn = fs / 2.
ks = 2. * np.pi * fs
kn = 2. * np.pi * fn
Nk = 151
# kv = np.logspace(-3, np.log10(1), Nk)
kv = np.linspace(0.01, 3, Nk)
wv = 2. * u_inf / ws.c_ref * kv

# # Analytical answer
Y_analytical = analytical.sears_fun(kv)

Y_freq_resp = libss.freqresp(sears_ss, wv) * u_inf / 2 / np.pi

Y_freq_resp_rom = libss.freqresp(rom.ssrom, wv)

save_variables(results_folder + 'freq_data_' + case_name + '.csv', [
    wv, kv, Y_analytical.real, Y_analytical.imag,
    Y_freq_resp_rom[0, 0, :].real, Y_freq_resp_rom[0, 0, :].imag,
    Y_freq_resp[0, 0, :].real, Y_freq_resp[0, 0, :].imag
], ('wv', 'kv', 'Y_sears_r', 'Y_sears_i', 'Y_ROM_r', 'Y_ROM_i', 'Y_FOM_r',
    'Y_FOM_i'))

sc_kussner_A = sears_ss.A
sc_kussner_B = sears_ss.B.copy()
sc_kussner_B.shape = (sc_kussner_A.shape[0], 1)
sc_kussner_C = sears_ss.C
sc_kussner_D = sears_ss.D.copy()
Exemplo n.º 3
0
# analytical
Yfreq_an = np.zeros((6, Nin_real, Nk), dtype=np.complex)
Yfreq_an[[0, 2, 4], :, :] = an.flat_plate_analytical(
    kv,
    x_ea_perc=main_ea,
    x_fh_perc=.9,
    input_seq=['plunge', 'pitch'],
    output_seq=['Fx', 'Fy', 'Mz'],
    output_scal=None,
    plunge_deriv=True)

# numerical
print('Full model frequency response started...')
t0 = time.time()
Yfreq_dummy_all = libss.freqresp(SStot, wv)
cputime = time.time() - t0
print('\t\t... done in %.2f sec!' % cputime)


def adjust_freq_resp(Yfreq_dummy):
    '''
    Given the freq. response in the structural degrees of freedom, this
    function scales the reponse and separates the output aerodynamic forces
    into those acting at the wing sections and total forces.

    The frequency response is always assumed to be in the input [h,dh,a,da].
    The pitch response is finally expressed in terms of a only setting
        da = jk a
    where k is the reduced frequency. The plunge response is in terms of dh
    instead.
Exemplo n.º 4
0
Nxbal=Ab.shape[0]


### tune ROM
# ROM is tuned under the assumption that the balanced system freq. response
# is exact.
ds=Sol.linuvlm.SS.dt
fs=1./ds
fn=fs/2.
ks=2.*np.pi*fs
kn=2.*np.pi*fn
# build freq. range
kmin,kmax,Nk=0.001,.5,30
kv=np.linspace(kmin,kmax,Nk)

Yfull=libss.freqresp(Sol.linuvlm.SS,kv,dlti=True)
Yb=libss.freqresp(SSb,kv,dlti=True)
Ybmax=np.max(np.abs(Yb))
erb=np.max(np.abs(Yb-Yfull))
print('Freq response error of balanced system: %.2e' %erb)
SSrom=librom.tune_rom(SSb,kv,tol=1e-6*Ybmax,gv=gv,method='realisation',convergence='all')

params=h5.ReadInto('params')
params.Nmodes=gebm.Nmodes
params.freq0=freq0.copy()
params.Nxfull=Sol.linuvlm.SS.A.shape[0]
params.cputime=cpubal
params.er_abs=erb
params.T=T
params.Ti=Ti