## Interpolating Logarithmic Plots for Fatigue Analysis -- Linear

July 4, 2018

Published in Design, Programming

Fatigue curves are typically in semi-log or log-log form. And in fatigue analysis it is often needed to interpolate both ways in order to determine stress or cycles. In both cases below we will interpolate over a straight line drawn on the graph using two points as its definition: \((N1,S1), (N2,S2).\)

## Semi-Log

In semi-log plots the stress is linear and the cycles are logarithmic. The equation of a line in this coordinate space is therefore:

\begin{equation}S=mlog10N+b\end{equation}

The values of \(m\) and \(b\) can be found by 2 known points on the fatigue curve:

\begin{align}

&m = \frac{\Delta S}{\Delta \log_{10}N} = \frac{S_2-S_1}{\log_{10}(N_2/N_1)}

&b = S_1 - m\log_{10}N_1

\end{align}

To get stress from cycles along this line, apply the equation of the line with your values of \(m\) and \(b\):

\begin{equation}

S(N) = m\log_{10}N + b

\end{equation}

To interpolate cycles from stress along this line, rearrange the equation for N:

\begin{equation}

N(S) = 10^{\frac{S-b}{m}}

\end{equation}

## Log-Log

Here both scales are logarithmic. The equation for a line in this coordinate system is therefore:

\begin{equation}

\log_{10}S = m \log_{10}N + \log_{10}b

\end{equation}

m and b are found in the same manner:

\begin{align}

&m = \frac{\Delta\log_{10}S}{\Delta\log_{10}N} = \frac{\log_{10}(S_2/S_1)}{\log_{10}(N_2/N_1)}

&b = 10^{\log_{10}S_1 - m \log_{10}N_1}

\end{align}

To interpolate stress from cycles:

\begin{equation}

S(N) = 10^{m\log_{10}N + \log_{10}b}

\end{equation}

To interpolate cycles from stress:

\begin{equation}

N(S) = 10^{ \frac{ \log_{10}S - \log_{10}b}{m} } = 10^{ \frac{\log_{10}(S/b)}{m} }

\end{equation}

## Python Implementation

In Python, we can make a class to represent a fatigue curve and give it methods for interpolation and plotting. Moreover, we can define a `__call__`

method to make the instance callable. For example:

```
"""
Provides classes for semi-log and log-log fatigue curves having methods for
interpolation and plotting.
"""
import numpy as np
import matplotlib.pyplot as plt
__author__ = 'Rob Siegwart'
__copyright__ = 'Copyright 2018 Rob Siegwart'
class FatigueCurve:
''' Base class for fatigue curves. Input:
A list containing two (N,S) data point pairs
'''
def __init__(self,points):
self.N, self.S = list(zip(points[0],points[1]))
self.N1, self.N2 = self.N
self.S1, self.S2 = self.S
def _plot(self):
''' Plot setup method '''
fig, ax = plt.subplots()
ax.set_xlabel('Cycles')
ax.set_ylabel('Stress')
ax.grid(True, which='both', axis='both', color='lightgrey')
return fig, ax
class SemiLogCurve(FatigueCurve):
def __init__(self,points):
super().__init__(points)
self.m = (self.S2 - self.S1)/np.log10(self.N2/self.N1)
self.b = self.S1 - self.m*np.log10(self.N1)
def getS(self,N,plot=False):
''' Interpolate stress from cycles. '''
S = np.round(self.m*np.log10(N) + self.b,2)
if plot:
fig,ax = self._plot()
ax.semilogx(self.N,self.S,N,S,'*')
return S
def getN(self,S,plot=False):
''' Interpolate cycles from stress. '''
N = int(10**((S-self.b)/self.m))
if plot:
fig,ax = self._plot()
ax.semilogx(self.N,self.S,N,S,'*')
return N
def plot(self):
fig, ax = self._plot()
ax.semilogx(self.N,self.S)
__call__ = getS
class LogLogCurve(FatigueCurve):
def __init__(self,points):
super().__init__(points)
self.m = np.log10(self.S2/self.S1)/np.log10(self.N2/self.N1)
self.b = 10**(np.log10(self.S1) - self.m*np.log10(self.N1))
def getS(self,N,plot=False):
''' Interpolate stress from cycles '''
S = np.round(10**(self.m*np.log10(N)+np.log10(self.b)),2)
if plot:
fig,ax = self._plot()
ax.loglog(self.N,self.S,N,S,'*')
return S
def getN(self,S,plot=False):
''' Interpolate cycles from stress '''
N = int(10**(np.log10(S/self.b)/self.m))
if plot:
fig,ax = self._plot()
ax.loglog(self.N,self.S,N,S,'*')
return N
def plot(self):
fig, ax = self._plot()
ax.loglog(self.N,self.S)
__call__ = getS
```

Usage:

```
>>> mat1 = SemiLogCurve([(1000,60),(1e6,20)]) # create a new curve
>>> mat1(3e5) # default call is interpolating to obtain stress from cycles
26.97
>>> mat1.getN(28.5,plot=True) # call to get cycles from stress input with plot set to True to generate a graph
230409
```