mirror of
https://github.com/mihakralj/QuanTAlib.git
synced 2026-08-20 11:38:05 +00:00
Class optimization
This commit is contained in:
+85
-66
@@ -1,4 +1,4 @@
|
||||
using System;
|
||||
using System.Runtime.CompilerServices;
|
||||
namespace QuanTAlib;
|
||||
|
||||
/// <summary>
|
||||
@@ -31,6 +31,12 @@ public class Mama : AbstractBase
|
||||
{
|
||||
private readonly double _fastLimit, _slowLimit;
|
||||
private readonly CircularBuffer _pr, _sm, _dt, _i1, _q1, _i2, _q2, _re, _im, _pd, _ph;
|
||||
private readonly double _twoPi = 2.0 * System.Math.PI;
|
||||
private readonly double _radToDeg = 180.0 / System.Math.PI;
|
||||
private readonly double _alpha02 = 0.2;
|
||||
private readonly double _alpha08 = 0.8;
|
||||
private readonly double _famaAlpha = 0.5;
|
||||
|
||||
private double _mama, _fama;
|
||||
private double _prevMama, _prevFama, _sumPr;
|
||||
private double _p_prevMama, _p_prevFama, _p_sumPr;
|
||||
@@ -40,12 +46,9 @@ public class Mama : AbstractBase
|
||||
/// </summary>
|
||||
public TValue Fama { get; private set; }
|
||||
|
||||
/// <param name="fastLimit">The maximum adaptation speed (default 0.5).</param>
|
||||
/// <param name="slowLimit">The minimum adaptation speed (default 0.05).</param>
|
||||
public Mama(double fastLimit = 0.5, double slowLimit = 0.05)
|
||||
{
|
||||
Fama = new TValue();
|
||||
Name = $"Mama({_fastLimit:F2}, {_slowLimit:F2})";
|
||||
_fastLimit = fastLimit;
|
||||
_slowLimit = slowLimit;
|
||||
_pr = new(7);
|
||||
@@ -59,23 +62,23 @@ public class Mama : AbstractBase
|
||||
_im = new(2);
|
||||
_pd = new(2);
|
||||
_ph = new(2);
|
||||
Name = $"Mama({_fastLimit:F2}, {_slowLimit:F2})";
|
||||
Init();
|
||||
}
|
||||
|
||||
/// <param name="source">The data source object that publishes updates.</param>
|
||||
/// <param name="fastLimit">The maximum adaptation speed (default 0.5).</param>
|
||||
/// <param name="slowLimit">The minimum adaptation speed (default 0.05).</param>
|
||||
public Mama(object source, double fastLimit = 0.5, double slowLimit = 0.05) : this(fastLimit, slowLimit)
|
||||
{
|
||||
var pubEvent = source.GetType().GetEvent("Pub");
|
||||
pubEvent?.AddEventHandler(source, new ValueSignal(Sub));
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
public override void Init()
|
||||
{
|
||||
Fama = new TValue();
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
protected override void ManageState(bool isNew)
|
||||
{
|
||||
if (isNew)
|
||||
@@ -94,6 +97,33 @@ public class Mama : AbstractBase
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private double CalculateSmooth()
|
||||
{
|
||||
return (4.0 * _pr[^1] + 3.0 * _pr[^2] + 2.0 * _pr[^3] + _pr[^4]) * 0.1;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private static double CalculateHilbertTransform(CircularBuffer buffer, double adj)
|
||||
{
|
||||
return (0.0962 * (buffer[^1] - buffer[^7]) + 0.5769 * (buffer[^3] - buffer[^5])) * adj;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private double CalculatePeriod(double im, double re)
|
||||
{
|
||||
if (im == 0 || re == 0) return _pd[^2];
|
||||
return _twoPi / System.Math.Atan(im / re);
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private double AdjustPeriod(double period)
|
||||
{
|
||||
period = System.Math.Clamp(period, 0.67 * _pd[^2], 1.5 * _pd[^2]);
|
||||
period = System.Math.Clamp(period, 6.0, 50.0);
|
||||
return _alpha02 * period + _alpha08 * _pd[^2];
|
||||
}
|
||||
|
||||
protected override double Calculation()
|
||||
{
|
||||
ManageState(Input.IsNew);
|
||||
@@ -102,85 +132,59 @@ public class Mama : AbstractBase
|
||||
|
||||
if (_index > 6)
|
||||
{
|
||||
double adj = (0.075 * _pd[^1]) + 0.54;
|
||||
double adj = 0.075 * _pd[^1] + 0.54;
|
||||
|
||||
// Smooth
|
||||
_sm.Add(((4 * _pr[^1]) + (3 * _pr[^2]) + (2 * _pr[^3]) + _pr[^4]) / 10, Input.IsNew);
|
||||
|
||||
// Detrender
|
||||
_dt.Add(((0.0962 * _sm[^1]) + (0.5769 * _sm[^3]) - (0.5769 * _sm[^5]) - (0.0962 * _sm[^7])) * adj, Input.IsNew);
|
||||
// Smooth and Detrender
|
||||
_sm.Add(CalculateSmooth(), Input.IsNew);
|
||||
_dt.Add(CalculateHilbertTransform(_sm, adj), Input.IsNew);
|
||||
|
||||
// In-phase and quadrature
|
||||
_q1.Add(((0.0962 * _dt[^1]) + (0.5769 * _dt[^3]) - (0.5769 * _dt[^5]) - (0.0962 * _dt[^7])) * adj, Input.IsNew);
|
||||
_q1.Add(CalculateHilbertTransform(_dt, adj), Input.IsNew);
|
||||
_i1.Add(_dt[^4], Input.IsNew);
|
||||
|
||||
// Advance the phases by 90 degrees
|
||||
double jI = ((0.0962 * _i1[^1]) + (0.5769 * _i1[^3]) - (0.5769 * _i1[^5]) - (0.0962 * _i1[^7])) * adj;
|
||||
double jQ = ((0.0962 * _q1[^1]) + (0.5769 * _q1[^3]) - (0.5769 * _q1[^5]) - (0.0962 * _q1[^7])) * adj;
|
||||
// Advance phases
|
||||
double jI = CalculateHilbertTransform(_i1, adj);
|
||||
double jQ = CalculateHilbertTransform(_q1, adj);
|
||||
|
||||
// Phasor addition for 3-bar averaging
|
||||
_i2.Add(_i1[^1] - jQ, Input.IsNew);
|
||||
_q2.Add(_q1[^1] + jI, Input.IsNew);
|
||||
_i2[^1] = 0.2 * _i2[^1] + 0.8 * _i2[^2];
|
||||
_q2[^1] = 0.2 * _q2[^1] + 0.8 * _q2[^2];
|
||||
// Phasor addition
|
||||
double i2 = _i1[^1] - jQ;
|
||||
double q2 = _q1[^1] + jI;
|
||||
_i2.Add(i2, Input.IsNew);
|
||||
_q2.Add(q2, Input.IsNew);
|
||||
_i2[^1] = _alpha02 * _i2[^1] + _alpha08 * _i2[^2];
|
||||
_q2[^1] = _alpha02 * _q2[^1] + _alpha08 * _q2[^2];
|
||||
|
||||
// Homodyne discriminator
|
||||
_re.Add((_i2[^1] * _i2[^2]) + (_q2[^1] * _q2[^2]), Input.IsNew);
|
||||
_im.Add((_i2[^1] * _q2[^2]) - (_q2[^1] * _i2[^2]), Input.IsNew);
|
||||
_re[^1] = (0.2 * _re[^1]) + (0.8 * _re[^2]);
|
||||
_im[^1] = (0.2 * _im[^1]) + (0.8 * _im[^2]);
|
||||
double re = _i2[^1] * _i2[^2] + _q2[^1] * _q2[^2];
|
||||
double im = _i2[^1] * _q2[^2] - _q2[^1] * _i2[^2];
|
||||
_re.Add(re, Input.IsNew);
|
||||
_im.Add(im, Input.IsNew);
|
||||
_re[^1] = _alpha02 * _re[^1] + _alpha08 * _re[^2];
|
||||
_im[^1] = _alpha02 * _im[^1] + _alpha08 * _im[^2];
|
||||
|
||||
// Calculate period
|
||||
if (_im[^1] != 0 && _re[^1] != 0)
|
||||
{
|
||||
_pd.Add(2 * Math.PI / Math.Atan(_im[^1] / _re[^1]), Input.IsNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
_pd.Add(_pd[^2], Input.IsNew);
|
||||
}
|
||||
// Calculate and adjust period
|
||||
double period = CalculatePeriod(_im[^1], _re[^1]);
|
||||
_pd.Add(period, Input.IsNew);
|
||||
_pd[^1] = AdjustPeriod(_pd[^1]);
|
||||
|
||||
// Adjust period to thresholds
|
||||
_pd[^1] = Math.Max(Math.Min(_pd[^1], 1.5 * _pd[^2]), 0.67 * _pd[^2]);
|
||||
_pd[^1] = Math.Max(Math.Min(_pd[^1], 50), 6);
|
||||
_pd[^1] = (0.2 * _pd[^1]) + (0.8 * _pd[^2]);
|
||||
// Phase calculation
|
||||
double phase = _i1[^1] != 0 ? System.Math.Atan(_q1[^1] / _i1[^1]) * _radToDeg : _ph[^2];
|
||||
_ph.Add(phase, Input.IsNew);
|
||||
|
||||
// Determine phase position
|
||||
if (_i1[^1] != 0)
|
||||
{
|
||||
_ph.Add(Math.Atan(_q1[^1] / _i1[^1]) * 180 / Math.PI, Input.IsNew);
|
||||
}
|
||||
else
|
||||
{
|
||||
_ph.Add(_ph[^2], Input.IsNew);
|
||||
}
|
||||
|
||||
// Change in phase
|
||||
double delta = Math.Max(_ph[^2] - _ph[^1], 1);
|
||||
|
||||
// Adaptive alpha value
|
||||
double alpha = Math.Max(_fastLimit / delta, _slowLimit);
|
||||
// Adaptive alpha
|
||||
double delta = System.Math.Max(_ph[^2] - _ph[^1], 1.0);
|
||||
double alpha = System.Math.Clamp(_fastLimit / delta, _slowLimit, _fastLimit);
|
||||
|
||||
// Final indicators
|
||||
_mama = alpha * (_pr[^1] - _prevMama) + _prevMama;
|
||||
_fama = 0.5 * alpha * (_mama - _prevFama) + _prevFama;
|
||||
_fama = _famaAlpha * alpha * (_mama - _prevFama) + _prevFama;
|
||||
|
||||
_prevMama = _mama;
|
||||
_prevFama = _fama;
|
||||
}
|
||||
else
|
||||
{
|
||||
_pd.Add(0, Input.IsNew);
|
||||
_sm.Add(0, Input.IsNew);
|
||||
_dt.Add(0, Input.IsNew);
|
||||
_i1.Add(0, Input.IsNew);
|
||||
_q1.Add(0, Input.IsNew);
|
||||
_i2.Add(0, Input.IsNew);
|
||||
_q2.Add(0, Input.IsNew);
|
||||
_re.Add(0, Input.IsNew);
|
||||
_im.Add(0, Input.IsNew);
|
||||
_ph.Add(0, Input.IsNew);
|
||||
|
||||
InitializeBuffers();
|
||||
_sumPr += Input.Value;
|
||||
_mama = _fama = _prevMama = _prevFama = _sumPr / _index;
|
||||
}
|
||||
@@ -190,4 +194,19 @@ public class Mama : AbstractBase
|
||||
|
||||
return _mama;
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
private void InitializeBuffers()
|
||||
{
|
||||
_pd.Add(0, Input.IsNew);
|
||||
_sm.Add(0, Input.IsNew);
|
||||
_dt.Add(0, Input.IsNew);
|
||||
_i1.Add(0, Input.IsNew);
|
||||
_q1.Add(0, Input.IsNew);
|
||||
_i2.Add(0, Input.IsNew);
|
||||
_q2.Add(0, Input.IsNew);
|
||||
_re.Add(0, Input.IsNew);
|
||||
_im.Add(0, Input.IsNew);
|
||||
_ph.Add(0, Input.IsNew);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user