ElectricPy
ElectricPy copied to clipboard
Adding `Frequency Response` for series and parallel `RLC` circuits to `electricpy.visu`
Describe the solution you'd like
- A clear and concise description of what you want to happen.
- Computing various parameters like
bandwidth
,quality factor
,resonating frequency,
and characteristic equation - Plotting the frequency response using matlplotlob
Link to Formulas and Example References
This sounds like a marvelous idea!
Do you have some content or ideas that you'd like to contribute, or is there something I can help with?
Yes I am having a very abstract idea for Frequency Response
as a class in visu.py
Which includes
-
RLC
Series Frequency Response -
Operation Amplifier
Frequency Response - Any Second order system with a given
characteristic equation
class FrequencyResponse:
def __init__(self) -> None:
pass
def band_width(self):
pass
def quality_factor():
pass
def lower_cut_off_frequency():
pass
def upper_cut_off_frequency():
pass
def peak_gain():
pass
class RLC(FrequencyResponse):
def __init__(self) -> None:
pass
class OpAmp(FrequencyResponse):
def __init__(self) -> None:
pass
I think this would be awesome!
Let me know how I can help!
class RLC(FrequencyResponse):
def __init__(self, resistance: float, inductance: float, capacitance: float, frequency: float) -> None:
self.resistance = resistance
self.inductance = inductance
self.capacitance = capacitance
self.frequency = frequency
def resonance_frequency(self):
return 1/(_np.sqrt(self.inductance*self.capacitance)*2*_np.pi)
def band_width(self):
return self.resistance/(2*_np.pi*self.inductance)
def quality_factor(self):
return 2*_np.pi*self.frequency/self.resistance
def lower_cut_off_frequency(self):
x = (-self.resistance)/(2*self.inductance)
resonance_angular_frequency = 2*_np.pi*self.resonance_frequency()
return (x + _np.sqrt(x**2 + resonance_angular_frequency**2))/(2*_np.pi)
def upper_cut_off_frequency(self):
x = (self.resistance)/(2*self.inductance)
resonance_angular_frequency = 2*_np.pi*self.resonance_frequency()
return (x + _np.sqrt(x**2 + resonance_angular_frequency**2))/(2*_np.pi)
def graph(self, lower_frequency_cut: float, upper_frequency_cut: float, samples = 10000):
x = _np.linspace(lower_frequency_cut, upper_frequency_cut, samples)
def output_gain(frequency):
ang_frq = 2*_np.pi*frequency
current_impedence = self.resistance**2 + (ang_frq*self.inductance - 1/(ang_frq*self.capacitance))**2
return (self.resistance)/(_np.sqrt(current_impedence))
y = output_gain(x)
_plt.title("Frequency response of series RLC circuit")
_plt.grid(visible=True)
_plt.plot(x, y)
_plt.ylabel("Gain")
_plt.xlabel("Frequency (Hz)")
f1, f2 = self.lower_cut_off_frequency(), self.upper_cut_off_frequency()
f = self.resonance_frequency()
_plt.scatter([f1, f2], [_np.sqrt(0.5), _np.sqrt(0.5)], marker="*", c="black", label='_nolegend_')
half_power_gain = _np.sqrt(0.5)
_plt.plot([f, f], [0, 1], ls='-.')
_plt.plot([f1, f1], [half_power_gain, 0], ls='-.')
_plt.plot([f2, f2], [half_power_gain, 0], ls='-.')
_plt.plot([f1, f2], [half_power_gain, half_power_gain], ls='-.')
_plt.plot([0, f], [half_power_gain, half_power_gain], label="_nolegend_", ls ="--")
_plt.plot([0, f], [1, 1], label="_nolegend_", ls ="--")
_plt.plot([0, 0], [half_power_gain, 1], label="Quality factor", c="black")
_plt.scatter([0], [half_power_gain], label="_nolegend_", c="black", marker='v')
_plt.scatter([0], [1], label="_nolegend_", c="black", marker='^')
_plt.legend([
'Gain',
f'Resonance frequency ({f}Hz)',
f'Lower cutoff frequency ({f1}Hz)',
f'Upper cutoff frequency ({f2}Hz)',
f'Bandwidth ({f2 - f1}Hz)',
f'Quality factor {self.quality_factor()}'
])
return _plt
Greeting,
- can you help me with documenting each and every function of above and this methods and classes
- should we take input in (uF, KHz) insted of (Farad and Hz)
Hi @Lakshmikanth2001! 👋
Regarding:
- should we take input in (uF, KHz) insted of (Farad and Hz)
I think that we should probably only accept units in Farads and Hz, since those seem to be the most prolific throughout the package, and consistency is key! Converting to those units is relatively easy, so it shouldn't be too troublesome.
Regarding:
- can you help me with documenting each and every function of above and this methods and classes
You bet! 😄 Happy to lend a hand, here!
Sample Python
class RLC(FrequencyResponse):
"""Frequency Response for a Traditional RLC (Resistive, Inductive, Capacitive) Load."""
def __init__(self, resistance: float, inductance: float, capacitance: float, frequency: float) -> None:
"""Form the Frequency Response Analysis System."""
self.resistance = resistance
self.inductance = inductance
self.capacitance = capacitance
self.frequency = frequency
@property
def resonance_frequency(self):
"""Resonance Frequency (in Hz) of the Described RLC Circuit."""
return 1/(_np.sqrt(self.inductance*self.capacitance)*2*_np.pi)
@property
def bandwidth(self):
"""Bandwidth of the Described RLC Circuit."""
return self.resistance/(2*_np.pi*self.inductance)
@property
def quality_factor(self):
"""Quality Factor of the Described RLC Circuit."""
return 2*_np.pi*self.frequency/self.resistance
@property
def lower_cutoff_frequency(self):
"""Lower Cutoff Frequency (in Hz) of the Described RLC Circuit."""
x = (-self.resistance)/(2*self.inductance)
resonance_angular_frequency = 2*_np.pi*self.resonance_frequency()
return (x + _np.sqrt(x**2 + resonance_angular_frequency**2))/(2*_np.pi)
@property
def upper_cut_off_frequency(self):
x = (self.resistance)/(2*self.inductance)
resonance_angular_frequency = 2*_np.pi*self.resonance_frequency()
return (x + _np.sqrt(x**2 + resonance_angular_frequency**2))/(2*_np.pi)
def output_gain(self, frequency: float):
"""
Evaluated Output Gain of the Described RLC Circuit at a Particular Frequency.
Parameters
-----------
frequency: float
Frequency (in Hz) at which the output gain should be evaluated.
"""
ang_frq = 2*_np.pi*frequency
current_impedence = self.resistance**2 + (ang_frq*self.inductance - 1/(ang_frq*self.capacitance))**2
return (self.resistance)/(_np.sqrt(current_impedence))
def graph(self, lower_frequency_cut: float, upper_frequency_cut: float, samples = 10000):
"""
Generate a Plot to Represent all Data Respective of the RLC Circuit.
Parameters
----------
lower_frequency_cut: float
Minimum frequency to demonstrate as a boundary of the X-axis of the plot.
upper_frequency_cut: float
Maximum frequency to demonstrate as a boundary of the X-axis of the plot.
samples: float
Number of samples over which the plot should be formed.
"""
x = _np.linspace(lower_frequency_cut, upper_frequency_cut, samples)
y = self.output_gain(x)
_plt.title("Frequency response of series RLC circuit")
_plt.grid(visible=True)
_plt.plot(x, y)
_plt.ylabel("Gain")
_plt.xlabel("Frequency (Hz)")
f1, f2 = self.lower_cut_off_frequency, self.upper_cut_off_frequency
f = self.resonance_frequency
_plt.scatter([f1, f2], [_np.sqrt(0.5), _np.sqrt(0.5)], marker="*", c="black", label='_nolegend_')
half_power_gain = _np.sqrt(0.5)
_plt.plot([f, f], [0, 1], ls='-.')
_plt.plot([f1, f1], [half_power_gain, 0], ls='-.')
_plt.plot([f2, f2], [half_power_gain, 0], ls='-.')
_plt.plot([f1, f2], [half_power_gain, half_power_gain], ls='-.')
_plt.plot([0, f], [half_power_gain, half_power_gain], label="_nolegend_", ls ="--")
_plt.plot([0, f], [1, 1], label="_nolegend_", ls ="--")
_plt.plot([0, 0], [half_power_gain, 1], label="Quality factor", c="black")
_plt.scatter([0], [half_power_gain], label="_nolegend_", c="black", marker='v')
_plt.scatter([0], [1], label="_nolegend_", c="black", marker='^')
_plt.legend([
'Gain',
f'Resonance frequency ({f}Hz)',
f'Lower cutoff frequency ({f1}Hz)',
f'Upper cutoff frequency ({f2}Hz)',
f'Bandwidth ({f2 - f1}Hz)',
f'Quality factor {self.quality_factor}'
])
return _plt
Please note that I've also added a few general suggestions in the layout of the class (mainly, I think that some of those methods could easily be properties, and that inner-function in the graph
method could be valuable by itself.
Thanks, @Lakshmikanth2001! 🎉
Let me know if you feel this issue is ready to close, or if you had other items you wish to add before we consider this work "done."
please test this changes from an end user perspective and give your valuable feedback we need to add Frequency Responses for
parallerl RLC
,OpAmp
and First and second order control systems etc which can complete the Frequency Response issue