Source code for pylife.stress.frequencysignal

# Copyright (c) 2019-2023 - for information on the respective copyright owner
# see the NOTICE file and/or the repository
# https://github.com/boschresearch/pylife
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""A module for frequency signal handling

Warning
-------

This module is not considered finalized even though it is part of pylife-2.0.
Breaking changes might occur in upcoming minor releases.
"""

import numpy as np
import pandas as pd
from scipy import optimize as op

[docs] class psdSignal: '''Handles different routines for self signals Remark: We are using the pandas data frame schema. The index contains the discrete frequency step. Every single column one self. Some functions of these class: * psd_optimizer * ... ''' def __init__(self,df): self.df = df
[docs] def rms_psd(self): f = np.logspace(np.log10(self.index.values.min()),np.log10( self.index.values.max()),2048) psd = pd.DataFrame() for colact in self.columns: psd[colact] = np.interp(f,self.index.values,self[colact]) psd.index = f return ((psd.diff()+psd).dropna()).multiply(np.diff(psd.index.values),axis = 0).sum()**0.5
def _intMinlog(self,psdin,fsel,factor_rms_nods): self_rms_df = pd.DataFrame(data = 10**np.interp(psdin.index.values, fsel,np.log10(self)), index = psdin.index.values) ysel = np.interp(fsel, psdin.index.values, psdin.values.flatten()) rms_in = psdSignal.rms_psd(psdin).values rms_smooth = psdSignal.rms_psd(self_rms_df).values eps1 = (rms_in-rms_smooth)**2/rms_in**2 eps2 = np.dot(np.log10(ysel/self),np.log10(ysel/self))/np.dot(np.log10(ysel),np.log10(ysel)) return factor_rms_nods*eps1+(1-factor_rms_nods)*eps2
[docs] def psd_smoother(self,fsel,factor_rms_nodes = 0.5): ''' Smoothen a PSD using nodes and a penalty factor weighting the errors for the RMS and for the node PSD values Parameters ---------- self: DataFrame unsmoothed PSD fsel: list or np.array nodes factor_rms_nodes: float (0 <= factor_rms_nods <= 1) penalty error weighting the errors: * 0: only error of node PSD values is considered * 1: only error of the RMS is considered Returns ------- DataFrame ''' f = np.logspace(np.log10(self.index.values.min()),np.log10( self.index.values.max()),1024) fsel = np.unique(fsel) fout = np.append(np.append(self.index.values.min(),np.unique(fsel)),self.index.values.max()) opt_df = pd.DataFrame() for colact in self.columns: df_in = pd.DataFrame(data = np.interp(f,self.index.values,self[colact]), index = f) Hi0 = 10**(np.interp(fsel,f,np.log10(df_in.values.flatten()))) lim = np.array([df_in.values.min()*np.ones_like(fsel), np.array(df_in.values.max()*np.ones_like(fsel))]).T Hi = op.minimize(psdSignal._intMinlog,x0 = Hi0,bounds = tuple(map(tuple, lim)), args=(df_in,fsel,factor_rms_nodes)) opt_df[colact] = 10**np.interp(fout,fsel,np.log10(Hi.x)) opt_df.index = fout return opt_df