Skip to content

Commit

Permalink
Merge pull request #7 from nvlinhvn/linh-dev
Browse files Browse the repository at this point in the history
Package and modulize hstransform
  • Loading branch information
nvlinhvn authored May 19, 2024
2 parents 6ed6726 + 134759e commit b02de97
Show file tree
Hide file tree
Showing 16 changed files with 365 additions and 19 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/pylint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
run: |
pylint $(git ls-files 'setup.py')
pylint $(git ls-files 'tests/__init__.py')
pylint --disable=C0114,C0103 $(git ls-files '__init__.py')
pylint --disable=E1101,W0212 $(git ls-files 'tests/test_hstransform.py')
pylint --disable=C0301,C0114 $(git ls-files 'hstransform.py')
pylint --disable=C0114,C0103 $(git ls-files 'hstransform/__init__.py')
pylint --disable=C0301,C0114 $(git ls-files 'hstransform/hstransform.py')
38 changes: 38 additions & 0 deletions .ipynb_checkpoints/setup-checkpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
"""
This is the setup module for the HSTransform package. (Beta test)
S-transform with Hyperbolic Window
Combines the best properties of the Short-time Fourier Transform
and the Wavelet Transform.
"""

from setuptools import setup, find_packages

with open("README.md", "r", encoding="utf-8") as fh:
long_description = fh.read()

setup(
name='HSTransform',
version='0.1.5',
url='https://github.com/nvlinhvn/HSTransform',
packages=find_packages(),
license='MIT',
author='Linh V Nguyen',
author_email='linhvietnguyen.ee@gmail.com',
description='A Package to Compute S-transform with Hyperbolic Window',
python_requires='>=3.10',
long_description=long_description,
long_description_content_type="text/markdown",
install_requires=[
'numpy>=1.21.2',
'scipy>=1.7.1',
'pandas>=1.3.3',
'pytest>=6.2.5'
],
classifiers=[
'Development Status :: 4 - Beta',
'License :: OSI Approved :: MIT License',
'Programming Language :: Python :: 3.10',
],
test_suite='tests'
)
50 changes: 41 additions & 9 deletions HSTransform.egg-info/PKG-INFO
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
Metadata-Version: 2.1
Name: HSTransform
Version: 0.2.1
Version: 0.1.5
Summary: A Package to Compute S-transform with Hyperbolic Window
Home-page: https://github.com/nvlinhvn/HSTransform
Author: Linh V Nguyen
Author-email: linhvietnguyen.ee@gmail.com
License: MIT
Expand All @@ -10,14 +11,27 @@ Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3.10
Requires-Python: >=3.10
Description-Content-Type: text/markdown
Requires-Dist: numpy>=1.21.2
Requires-Dist: scipy>=1.7.1
Requires-Dist: pandas>=1.3.3
Requires-Dist: pytest>=6.2.5

# Hyperbolic S-Transform

Package for Hyperbolic S-transform

## 1. Introduction

HS Transform is a Python package for performing Hyperbolic S-transforms. The S-transform is a time-frequency representation that combines the best properties of the Short-time Fourier Transform and the Wavelet Transform. It provides simultaneous information on both the frequency content and temporal localization of a signal.
HS Transform is a Python package for performing Hyperbolic [S-transform](https://en.wikipedia.org/wiki/S_transform) [[1]](#1). The S-transform is a time-frequency representation that combines the best properties of the Short-time Fourier Transform and the Wavelet Transform. It provides simultaneous information on both the frequency content and temporal localization of a signal.

This is a work of my [published paper](https://ieeexplore.ieee.org/document/8423487)

### References

<a id="1">[1]</a>
Stockwell, R.G., Mansinha, L. & Lowe, R.P., (1996).
Localization of the complex spectrum: the S transform.
IEEE Trans. Signal Process., 44(4), 998–1001, doi:10.1109/78.492555

## 2. Dependencies

Expand Down Expand Up @@ -46,8 +60,8 @@ After installation, you can test the package using the included test scripts:

Here’s an example of how to use HS Transform to analyze a signal with voltage disturbance and power system fault:

```
from hstransform import HyperbolicSTransform as HSTransform
```python
from hstransform import HSTransform

# Create input signal (for example: Voltage signal)
t = np.linspace(0, 10, 100) # timeseries
Expand All @@ -65,13 +79,31 @@ hs = HSTransform()

# Perform the transform
signal = V_sag
S_transformed = st.fit_transform(t, signal)
S_transformed = hs.fit_transform(t, signal)
```

![alt text](./img/power_quality_disturbance.png)
![alt text](./img/power_quality_disturbance_trajectory.png)
![alt text](./img/fault_current.png)
![alt text](./img/fault_trajectory.png)
### 5.1 Power Quality Disturbance

![Voltage Disturbance](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/power_quality_disturbance.png)

The figure showed HS-transform is able to detect the transient disturbances like notch, spike. Meanwhile, those signals from Morlet Wavelet transform are not obviously recognized.

######

![Real-Imag Trajectory](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/power_quality_disturbance_trajectory.png)
We can see also different types of voltage disturbance can generate different real-imaginary trajectory in S-transform at different frequencies.

### 5.2 Power System Faults

![Different Faults](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/fault_current.png)

As can be seen, both Wavelet and S-transform are able to detect when the fault occur (huge change in current magnitude). Wavelet transform seems more sensitive with noise with high distortion compared with HS-transform.

######

![Real-Imag Trajectory](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/fault_trajectory.png)

We can also observe different types of faults can generate different real-imaginary trajectory in S-transform at varying levels of frequencies.

## 6. Communication

Expand Down
2 changes: 2 additions & 0 deletions HSTransform.egg-info/SOURCES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,7 @@ HSTransform.egg-info/SOURCES.txt
HSTransform.egg-info/dependency_links.txt
HSTransform.egg-info/requires.txt
HSTransform.egg-info/top_level.txt
hstransform/__init__.py
hstransform/hstransform.py
tests/__init__.py
tests/test_hstransform.py
1 change: 0 additions & 1 deletion HSTransform.egg-info/requires.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
numpy>=1.21.2
scipy>=1.7.1
pandas>=1.3.3
matplotlib>=3.4.3
pytest>=6.2.5
1 change: 1 addition & 0 deletions HSTransform.egg-info/top_level.txt
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
hstransform
tests
12 changes: 8 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,24 @@ S_transformed = hs.fit_transform(t, signal)

### 5.1 Power Quality Disturbance

![](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/power_quality_disturbance.png)
![Voltage Disturbance](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/power_quality_disturbance.png)

The figure showed HS-transform is able to detect the transient disturbances like notch, spike. Meanwhile, those signals from Morlet Wavelet transform are not obviously recognized.

![](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/power_quality_disturbance_trajectory.png)
######

![Real-Imag Trajectory](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/power_quality_disturbance_trajectory.png)
We can see also different types of voltage disturbance can generate different real-imaginary trajectory in S-transform at different frequencies.

### 5.2 Power System Faults

![](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/fault_current.png)
![Different Faults](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/fault_current.png)

As can be seen, both Wavelet and S-transform are able to detect when the fault occur (huge change in current magnitude). Wavelet transform seems more sensitive with noise with high distortion compared with HS-transform.

![](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/fault_trajectory.png)
######

![Real-Imag Trajectory](https://raw.githubusercontent.com/nvlinhvn/HSTransform/main/img/fault_trajectory.png)

We can also observe different types of faults can generate different real-imaginary trajectory in S-transform at varying levels of frequencies.

Expand Down
File renamed without changes.
135 changes: 135 additions & 0 deletions build/lib/hstransform/hstransform.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
import dataclasses
from typing import Union

import numpy as np
from scipy.fft import fft, ifft
import pandas as pd


@dataclasses.dataclass
class HSTransform:
"""
A class used to represent the S-transform with a hyperbolic Gaussian window.
...
Attributes
----------
forwardtaper : float
forward taper value
backwardtaper : float
backward taper value
curvature : float
curvature value
"""

forwardtaper: float = 0.2
backwardtaper: float = 0.1
curvature: float = 312.5

def _input_validation(self, input_signal):
"""
Validates the input signal.
Parameters
----------
input_signal : np.ndarray, pd.Series, or list
Raises
------
TypeError: If input_signal is not a numpy array, pandas Series, or list.
ValueError: If input_signal contains non-numerical values.
"""
valid_types = (np.ndarray, pd.Series, list)
if not isinstance(input_signal, valid_types):
raise TypeError(f"input_signal must be one of the following types: {valid_types}, not {type(input_signal)}.")

input_array = np.array(input_signal)
if np.isnan(input_array).any():
raise ValueError("input_signal contains null values.")

if not np.issubdtype(input_array.dtype, np.number):
raise ValueError("input_signal should only contain numerical values.")

def _compute_hyperbolic_gaussian(self, l: int, n: int, time: np.ndarray) -> np.ndarray:
"""
Computes the hyperbolic Gaussian window.
Parameters
----------
l : int
length of the signal
n : int
frequency point
time : np.ndarray
time values of the signal
Returns
-------
g : np.ndarray
hyperbolic Gaussian window
"""
vectorf = np.arange(0, l)
vectorf1 = vectorf**2
lambdaf = self.forwardtaper
lambdab = self.backwardtaper
lambda_val = self.curvature
x = (lambdaf + lambdab) * time / (2 * lambdaf * lambdab) + (lambdaf - lambdab) * np.sqrt(time**2 + lambda_val) / (2 * lambdaf * lambdab)
x = np.tile(x, (1, 2)).T
vectorf2 = -vectorf1 * x**2 / (2 * n**2)
g = 2 * np.abs(vectorf) * np.exp(vectorf2) / ((lambdaf + lambdab) * np.sqrt(2 * np.pi))
return np.sum(g)

def fit_transform(self,
time_values: Union[pd.Series, np.ndarray, list],
input_signal: Union[pd.Series, np.ndarray, list],
minf: int = 0,
fsamplingrate: int = 1) -> np.ndarray:
"""
Computes the S-transform of the input signal.
Parameters
----------
time_values : np.ndarray
time values of the signal
input_signal : np.ndarray
input signal
minf : int
minimum frequency point
fsamplingrate : int
frequency sampling rate
Returns
-------
S : np.ndarray
S-transform of the input signal
"""
# Validate the input
self._input_validation(input_signal)

# Convert to numpy arrays if they are not array types
if not isinstance(time_values, np.ndarray):
time_values = np.array(time_values)
if not isinstance(input_signal, np.ndarray):
input_signal = np.array(input_signal)

n = len(input_signal)
# Make sure the max frequency to be optimized (Cover the 6th, 12th, or 18th harmonic respectively)
maxf = min(900, n // 2)

# Compute the fft of input
h = fft(input_signal)
h = np.concatenate((h, h))

# S output
s = np.zeros(((maxf - minf + 1) // fsamplingrate, n), dtype='complex')
s[0, :] = np.mean(input_signal) * (1 & np.arange(1, n + 1))

# Increment the frequency point
for k in range(fsamplingrate, maxf - minf + 1, fsamplingrate):
w_hy = self._compute_hyperbolic_gaussian(n, minf + k, time_values)
s[k // fsamplingrate, :] = ifft(h[minf + k + 1:minf + k + n+1] * w_hy)

return s


1 change: 1 addition & 0 deletions hstransform/.ipynb_checkpoints/__init__-checkpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .hstransform import HSTransform
File renamed without changes.
1 change: 1 addition & 0 deletions hstransform/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from .hstransform import HSTransform
Loading

0 comments on commit b02de97

Please sign in to comment.