feat(cycles): add AMFM - Ehlers AM Detector / FM Demodulator

This commit is contained in:
Miha Kralj
2026-03-17 15:56:55 -07:00
parent e17b00172a
commit d3cb9d2513
14 changed files with 1240 additions and 0 deletions
+1
View File
@@ -571,6 +571,7 @@ HAS_DSP = _bind("qtl_dsp", [_dp, _ci, _dp, _ci])
HAS_CCOR = _bind("qtl_ccor", [_dp, _ci, _dp, _ci, _cd])
HAS_EBSW = _bind("qtl_ebsw", [_dp, _ci, _dp, _ci, _ci])
HAS_ACP = _bind("qtl_acp", [_dp, _ci, _dp, _ci, _ci, _ci, _ci])
HAS_AMFM = _bind("qtl_amfm", [_dp, _dp, _ci, _dp, _dp, _ci])
# ── Numerics (Exports.cs — manual) ──
HAS_CHANGE = _bind("qtl_change", [_dp, _ci, _dp, _ci])
+11
View File
@@ -21,6 +21,7 @@ __all__ = [
"ccor",
"ebsw",
"acp",
"amfm",
]
@@ -150,3 +151,13 @@ def acp(close: object, min_period: int = 8, max_period: int = 48,
src, idx = _arr(close); n = len(src); dst = _out(n)
_check(_lib.qtl_acp(_ptr(src), n, _ptr(dst), int(min_period), int(max_period), int(avg_length), int(enhance)))
return _wrap(dst, idx, f"ACP_{min_period}_{max_period}", "cycles", offset)
def amfm(open: object, close: object, period: int = 30,
offset: int = 0, **kwargs) -> object:
"""Ehlers AM Detector / FM Demodulator."""
period = int(kwargs.get("length", period)); offset = int(offset)
o, idx = _arr(open); c, _ = _arr(close)
n = len(o); fm = _out(n); am = _out(n)
_check(_lib.qtl_amfm(_ptr(o), _ptr(c), n, _ptr(fm), _ptr(am), period))
return _wrap_multi({f"FM_{period}": fm, f"AM_{period}": am}, idx, "cycles", offset)
+11
View File
@@ -1525,6 +1525,17 @@ public static unsafe partial class Exports
catch { return StatusCodes.QTL_ERR_INTERNAL; }
}
// Amfm: Pattern OC-dual (open, close → fmOut, amOut, int period)
[UnmanagedCallersOnly(EntryPoint = "qtl_amfm")]
public static int QtlAmfm(double* open, double* close, int n, double* dstFm, double* dstAm, int period)
{
if (open == null || close == null || dstFm == null || dstAm == null) return StatusCodes.QTL_ERR_NULL_PTR;
if (n <= 0) return StatusCodes.QTL_ERR_INVALID_LENGTH;
int v = ChkPeriod(period); if (v != 0) return v;
try { Amfm.Batch(Src(open, n), Src(close, n), Dst(dstAm, n), Dst(dstFm, n), period); return StatusCodes.QTL_OK; }
catch { return StatusCodes.QTL_ERR_INTERNAL; }
}
// ═══════════════════════════════════════════════════════════════════════
// §8.14 Numerics / transforms
// ═══════════════════════════════════════════════════════════════════════