From c072d085dadd511701e43cf43840993c70da6958 Mon Sep 17 00:00:00 2001 From: Shreya123714 Date: Wed, 30 Oct 2024 16:46:13 +0530 Subject: [PATCH 01/12] Add guassian fuzzy set and its operations --- fuzzy_logic/gaussian_fuzzyset.py | 93 ++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) create mode 100644 fuzzy_logic/gaussian_fuzzyset.py diff --git a/fuzzy_logic/gaussian_fuzzyset.py b/fuzzy_logic/gaussian_fuzzyset.py new file mode 100644 index 000000000000..8ca8947d98ac --- /dev/null +++ b/fuzzy_logic/gaussian_fuzzyset.py @@ -0,0 +1,93 @@ +""" +By @Shreya123714 + +https://en.wikipedia.org/wiki/Fuzzy_set +https://en.wikipedia.org/wiki/Fuzzy_set_operations +https://en.wikipedia.org/wiki/Membership_function_(mathematics) +""" + +from __future__ import annotations +from dataclasses import dataclass +import numpy as np +import matplotlib.pyplot as plt + +@dataclass +class GaussianFuzzySet: + """ + A class for representing and manipulating Gaussian fuzzy sets. + + Attributes: + name: The name or label of the fuzzy set. + mean: The mean value (center) of the Gaussian fuzzy set. + std_dev: The standard deviation (controls the spread) of the Gaussian fuzzy set. + is_complement: Indicates whether this is the complement of the original fuzzy set. + + Methods: + membership(x): Calculate the membership value of an input 'x' in the fuzzy set. + complement(): Create a new GaussianFuzzySet instance representing the complement. + plot(): Plot the membership function of the fuzzy set. + + >>> fuzzy_set = GaussianFuzzySet("Medium Temperature", mean=25, std_dev=5) + >>> fuzzy_set.membership(25) + 1.0 + >>> fuzzy_set.membership(30) + 0.6065306597126334 + >>> fuzzy_set.complement().membership(25) + 0.0 + """ + + name: str + mean: float + std_dev: float + is_complement: bool = False # This flag indicates if it's the complement set + + def membership(self, x: float) -> float: + """ + Calculate the membership value of an input 'x' in the Gaussian fuzzy set. + If it's a complement set, returns 1 - the Gaussian membership. + + >>> GaussianFuzzySet("Medium", 0, 1).membership(0) + 1.0 + >>> GaussianFuzzySet("Medium", 0, 1).membership(1) + 0.6065306597126334 + """ + membership_value = np.exp(-0.5 * ((x - self.mean) / self.std_dev) ** 2) + return 1 - membership_value if self.is_complement else membership_value + + def complement(self) -> GaussianFuzzySet: + """ + Create a new GaussianFuzzySet instance representing the complement. + + >>> GaussianFuzzySet("Medium", 0, 1).complement().membership(0) + 0.0 + """ + return GaussianFuzzySet(f"¬{self.name}", self.mean, self.std_dev, is_complement=not self.is_complement) + + def plot(self): + """ + Plot the membership function of the Gaussian fuzzy set. + """ + x = np.linspace(self.mean - 3 * self.std_dev, self.mean + 3 * self.std_dev, 1000) + y = [self.membership(xi) for xi in x] + plt.plot(x, y, label=self.name) + plt.xlabel("x") + plt.ylabel("Membership") + plt.legend() + +if __name__ == "__main__": + from doctest import testmod + testmod() + + # Create an instance of GaussianFuzzySet + fuzzy_set = GaussianFuzzySet("Medium Temperature", mean=25, std_dev=5) + + # Display some membership values + print(f"Membership at mean (25): {fuzzy_set.membership(25)}") + print(f"Membership at 30: {fuzzy_set.membership(30)}") + print(f"Complement Membership at mean (25): {fuzzy_set.complement().membership(25)}") + + # Plot the Gaussian Fuzzy Set and its complement + fuzzy_set.plot() + fuzzy_set.complement().plot() + plt.title("Gaussian Fuzzy Set and its Complement") + plt.show() From 44ae96e34a8a92b8bc463f4f44b0617f3a549ec9 Mon Sep 17 00:00:00 2001 From: Shreya123714 Date: Thu, 31 Oct 2024 00:32:58 +0530 Subject: [PATCH 02/12] delete --- fuzzy_logic/gaussian_fuzzyset.py | 93 -------------------------------- 1 file changed, 93 deletions(-) delete mode 100644 fuzzy_logic/gaussian_fuzzyset.py diff --git a/fuzzy_logic/gaussian_fuzzyset.py b/fuzzy_logic/gaussian_fuzzyset.py deleted file mode 100644 index 8ca8947d98ac..000000000000 --- a/fuzzy_logic/gaussian_fuzzyset.py +++ /dev/null @@ -1,93 +0,0 @@ -""" -By @Shreya123714 - -https://en.wikipedia.org/wiki/Fuzzy_set -https://en.wikipedia.org/wiki/Fuzzy_set_operations -https://en.wikipedia.org/wiki/Membership_function_(mathematics) -""" - -from __future__ import annotations -from dataclasses import dataclass -import numpy as np -import matplotlib.pyplot as plt - -@dataclass -class GaussianFuzzySet: - """ - A class for representing and manipulating Gaussian fuzzy sets. - - Attributes: - name: The name or label of the fuzzy set. - mean: The mean value (center) of the Gaussian fuzzy set. - std_dev: The standard deviation (controls the spread) of the Gaussian fuzzy set. - is_complement: Indicates whether this is the complement of the original fuzzy set. - - Methods: - membership(x): Calculate the membership value of an input 'x' in the fuzzy set. - complement(): Create a new GaussianFuzzySet instance representing the complement. - plot(): Plot the membership function of the fuzzy set. - - >>> fuzzy_set = GaussianFuzzySet("Medium Temperature", mean=25, std_dev=5) - >>> fuzzy_set.membership(25) - 1.0 - >>> fuzzy_set.membership(30) - 0.6065306597126334 - >>> fuzzy_set.complement().membership(25) - 0.0 - """ - - name: str - mean: float - std_dev: float - is_complement: bool = False # This flag indicates if it's the complement set - - def membership(self, x: float) -> float: - """ - Calculate the membership value of an input 'x' in the Gaussian fuzzy set. - If it's a complement set, returns 1 - the Gaussian membership. - - >>> GaussianFuzzySet("Medium", 0, 1).membership(0) - 1.0 - >>> GaussianFuzzySet("Medium", 0, 1).membership(1) - 0.6065306597126334 - """ - membership_value = np.exp(-0.5 * ((x - self.mean) / self.std_dev) ** 2) - return 1 - membership_value if self.is_complement else membership_value - - def complement(self) -> GaussianFuzzySet: - """ - Create a new GaussianFuzzySet instance representing the complement. - - >>> GaussianFuzzySet("Medium", 0, 1).complement().membership(0) - 0.0 - """ - return GaussianFuzzySet(f"¬{self.name}", self.mean, self.std_dev, is_complement=not self.is_complement) - - def plot(self): - """ - Plot the membership function of the Gaussian fuzzy set. - """ - x = np.linspace(self.mean - 3 * self.std_dev, self.mean + 3 * self.std_dev, 1000) - y = [self.membership(xi) for xi in x] - plt.plot(x, y, label=self.name) - plt.xlabel("x") - plt.ylabel("Membership") - plt.legend() - -if __name__ == "__main__": - from doctest import testmod - testmod() - - # Create an instance of GaussianFuzzySet - fuzzy_set = GaussianFuzzySet("Medium Temperature", mean=25, std_dev=5) - - # Display some membership values - print(f"Membership at mean (25): {fuzzy_set.membership(25)}") - print(f"Membership at 30: {fuzzy_set.membership(30)}") - print(f"Complement Membership at mean (25): {fuzzy_set.complement().membership(25)}") - - # Plot the Gaussian Fuzzy Set and its complement - fuzzy_set.plot() - fuzzy_set.complement().plot() - plt.title("Gaussian Fuzzy Set and its Complement") - plt.show() From aeafc969a5242d59d6e08f8054ac1824102f8bec Mon Sep 17 00:00:00 2001 From: Shreya123714 Date: Thu, 31 Oct 2024 01:08:05 +0530 Subject: [PATCH 03/12] Added a Exp. moving average filter to smooth audio signal --- audio_filters/ema_filter.py | 67 +++++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) create mode 100644 audio_filters/ema_filter.py diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py new file mode 100644 index 000000000000..2786cd110ff3 --- /dev/null +++ b/audio_filters/ema_filter.py @@ -0,0 +1,67 @@ +""" +By @Shreya123714 + +https://en.wikipedia.org/wiki/Moving_average +""" + +import numpy as np +from typing import List + +class EMAFilter: + """ + A class for applying an Exponential Moving Average (EMA) filter + to audio data. + + Attributes: + alpha (float): Smoothing factor where 0 < alpha <= 1. + ema_value (float): Stores the most recent EMA value + for the ongoing calculation. + """ + + def __init__(self, alpha: float) -> None: + """ + Initialize the Exponential Moving Average (EMA) filter. + + Parameters: + alpha (float): Smoothing factor where 0 < alpha <= 1. + + Raises: + ValueError: If alpha is not within the range (0, 1]. + """ + if not (0 < alpha <= 1): + raise ValueError("Alpha must be between 0 and 1.") + self.alpha = alpha + self.ema_value = None + + def apply(self, audio_signal: List[float]) -> np.ndarray: + """ + Apply the EMA filter to a sequence of + audio signal values. + + Parameters: + audio_signal (List[float]): List of numerical values + representing the audio signal. + + Returns: + np.ndarray: Array containing the smoothed audio signal. + + Example: + >>> ema_filter = EMAFilter(0.2) + >>> np.allclose(ema_filter.apply([0.1, 0.5, 0.8, 0.6, 0.3, 0.9, 0.4]), + ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584]) + True + """ + ema_signal = [] + for sample in audio_signal: + if self.ema_value is None: + # Initialize the EMA with the first sample + self.ema_value = sample + else: + # Calculate the EMA for the current sample + self.ema_value = self.alpha * sample + (1 - self.alpha) * self.ema_value + ema_signal.append(self.ema_value) + return np.array(ema_signal) + +if __name__ == "__main__": + import doctest + doctest.testmod() From 1f1c1b073c8ccdbf10adf95533b3ba50c0b0ee02 Mon Sep 17 00:00:00 2001 From: Shreya123714 Date: Wed, 30 Oct 2024 19:38:37 +0000 Subject: [PATCH 04/12] updating DIRECTORY.md --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index f0a34a553946..7bf42a13622b 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -1,6 +1,7 @@ ## Audio Filters * [Butterworth Filter](audio_filters/butterworth_filter.py) + * [Ema Filter](audio_filters/ema_filter.py) * [Iir Filter](audio_filters/iir_filter.py) * [Show Response](audio_filters/show_response.py) From 2e1193507b5cbdaaed148221f66e000d82699c3e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:43:34 +0000 Subject: [PATCH 05/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- audio_filters/ema_filter.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index 2786cd110ff3..12b62b318f36 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -7,11 +7,12 @@ import numpy as np from typing import List + class EMAFilter: """ A class for applying an Exponential Moving Average (EMA) filter to audio data. - + Attributes: alpha (float): Smoothing factor where 0 < alpha <= 1. ema_value (float): Stores the most recent EMA value @@ -24,7 +25,7 @@ def __init__(self, alpha: float) -> None: Parameters: alpha (float): Smoothing factor where 0 < alpha <= 1. - + Raises: ValueError: If alpha is not within the range (0, 1]. """ @@ -47,7 +48,7 @@ def apply(self, audio_signal: List[float]) -> np.ndarray: Example: >>> ema_filter = EMAFilter(0.2) - >>> np.allclose(ema_filter.apply([0.1, 0.5, 0.8, 0.6, 0.3, 0.9, 0.4]), + >>> np.allclose(ema_filter.apply([0.1, 0.5, 0.8, 0.6, 0.3, 0.9, 0.4]), ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584]) True """ @@ -62,6 +63,8 @@ def apply(self, audio_signal: List[float]) -> np.ndarray: ema_signal.append(self.ema_value) return np.array(ema_signal) + if __name__ == "__main__": import doctest + doctest.testmod() From 435591475d5549528489af2b67070d5d0fc4ddf4 Mon Sep 17 00:00:00 2001 From: Shreya <95279016+Shreya123714@users.noreply.github.com> Date: Thu, 31 Oct 2024 01:23:36 +0530 Subject: [PATCH 06/12] Update ema_filter.py --- audio_filters/ema_filter.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index 12b62b318f36..2543829bb9ae 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -5,7 +5,7 @@ """ import numpy as np -from typing import List +from typing import Any class EMAFilter: @@ -34,13 +34,13 @@ def __init__(self, alpha: float) -> None: self.alpha = alpha self.ema_value = None - def apply(self, audio_signal: List[float]) -> np.ndarray: + def apply(self, audio_signal: list[float]) -> np.ndarray: """ Apply the EMA filter to a sequence of audio signal values. Parameters: - audio_signal (List[float]): List of numerical values + audio_signal (list[float]): List of numerical values representing the audio signal. Returns: From 47a6069968f49a4e0029933533bfddef005d010f Mon Sep 17 00:00:00 2001 From: Shreya <95279016+Shreya123714@users.noreply.github.com> Date: Thu, 31 Oct 2024 01:27:45 +0530 Subject: [PATCH 07/12] Update ema_filter.py --- audio_filters/ema_filter.py | 1 - 1 file changed, 1 deletion(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index 2543829bb9ae..9c4957277f3b 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -5,7 +5,6 @@ """ import numpy as np -from typing import Any class EMAFilter: From 06775c4bf5a21e627fecec3c4a30305a9297d980 Mon Sep 17 00:00:00 2001 From: Shreya <95279016+Shreya123714@users.noreply.github.com> Date: Thu, 31 Oct 2024 01:33:49 +0530 Subject: [PATCH 08/12] Update ema_filter.py --- audio_filters/ema_filter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index 9c4957277f3b..cb7a0d644ecc 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -31,7 +31,7 @@ def __init__(self, alpha: float) -> None: if not (0 < alpha <= 1): raise ValueError("Alpha must be between 0 and 1.") self.alpha = alpha - self.ema_value = None + self.ema_value = 0.0 def apply(self, audio_signal: list[float]) -> np.ndarray: """ @@ -51,7 +51,7 @@ def apply(self, audio_signal: list[float]) -> np.ndarray: ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584]) True """ - ema_signal = [] + ema_signal: list[float] = [] for sample in audio_signal: if self.ema_value is None: # Initialize the EMA with the first sample From 235d527b9f7fded3503bc57087446f26fe026391 Mon Sep 17 00:00:00 2001 From: Shreya <95279016+Shreya123714@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:15:46 +0530 Subject: [PATCH 09/12] Update ema_filter.py np.allclose() function now has tighter tolerance values, with rtol=1e-5 and atol=1e-8 --- audio_filters/ema_filter.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index cb7a0d644ecc..8f63c5b129d1 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -48,7 +48,8 @@ def apply(self, audio_signal: list[float]) -> np.ndarray: Example: >>> ema_filter = EMAFilter(0.2) >>> np.allclose(ema_filter.apply([0.1, 0.5, 0.8, 0.6, 0.3, 0.9, 0.4]), - ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584]) + ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584] + ... rtol=1e-5, atol=1e-8) True """ ema_signal: list[float] = [] From cd66f4f5320e79895622704c886c775c55c74e76 Mon Sep 17 00:00:00 2001 From: Shreya <95279016+Shreya123714@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:48:05 +0530 Subject: [PATCH 10/12] Update ema_filter.py Corrected the build error , caused due to return of None by apply() --- audio_filters/ema_filter.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index 8f63c5b129d1..d368f53ca3dd 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -33,6 +33,8 @@ def __init__(self, alpha: float) -> None: self.alpha = alpha self.ema_value = 0.0 + + def apply(self, audio_signal: list[float]) -> np.ndarray: """ Apply the EMA filter to a sequence of @@ -48,19 +50,21 @@ def apply(self, audio_signal: list[float]) -> np.ndarray: Example: >>> ema_filter = EMAFilter(0.2) >>> np.allclose(ema_filter.apply([0.1, 0.5, 0.8, 0.6, 0.3, 0.9, 0.4]), - ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584] + ... [0.1, 0.18, 0.304, 0.3632, 0.35056, 0.460448, 0.4483584], ... rtol=1e-5, atol=1e-8) True """ + if not audio_signal: + return np.array([]) + ema_signal: list[float] = [] - for sample in audio_signal: + self.ema_value = audio_signal[0] + ema_signal.append(self.ema_value) + + for sample in audio_signal[1:]: if self.ema_value is None: - # Initialize the EMA with the first sample - self.ema_value = sample - else: - # Calculate the EMA for the current sample self.ema_value = self.alpha * sample + (1 - self.alpha) * self.ema_value - ema_signal.append(self.ema_value) + ema_signal.append(self.ema_value) return np.array(ema_signal) From 28edd2bdd7fd4a3762ac8d6fd952f7395dc9337a Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 31 Oct 2024 04:18:27 +0000 Subject: [PATCH 11/12] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- audio_filters/ema_filter.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index d368f53ca3dd..e863c5a0131c 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -33,8 +33,6 @@ def __init__(self, alpha: float) -> None: self.alpha = alpha self.ema_value = 0.0 - - def apply(self, audio_signal: list[float]) -> np.ndarray: """ Apply the EMA filter to a sequence of @@ -56,11 +54,11 @@ def apply(self, audio_signal: list[float]) -> np.ndarray: """ if not audio_signal: return np.array([]) - + ema_signal: list[float] = [] self.ema_value = audio_signal[0] ema_signal.append(self.ema_value) - + for sample in audio_signal[1:]: if self.ema_value is None: self.ema_value = self.alpha * sample + (1 - self.alpha) * self.ema_value From da736cf45acf3e838297886cfe706417f2b3cada Mon Sep 17 00:00:00 2001 From: Shreya <95279016+Shreya123714@users.noreply.github.com> Date: Thu, 31 Oct 2024 09:53:53 +0530 Subject: [PATCH 12/12] Update ema_filter.py Corrected the error , now it will run :) --- audio_filters/ema_filter.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/audio_filters/ema_filter.py b/audio_filters/ema_filter.py index e863c5a0131c..56dcc2e850ef 100644 --- a/audio_filters/ema_filter.py +++ b/audio_filters/ema_filter.py @@ -60,9 +60,8 @@ def apply(self, audio_signal: list[float]) -> np.ndarray: ema_signal.append(self.ema_value) for sample in audio_signal[1:]: - if self.ema_value is None: - self.ema_value = self.alpha * sample + (1 - self.alpha) * self.ema_value - ema_signal.append(self.ema_value) + self.ema_value = self.alpha * sample + (1 - self.alpha) * self.ema_value + ema_signal.append(self.ema_value) return np.array(ema_signal)