From 7772db312351544ccf70b0a58962c2e446869e0b Mon Sep 17 00:00:00 2001 From: Jiahao Yuan Date: Fri, 7 Jul 2023 20:10:43 +0800 Subject: [PATCH] feat: :sparkles: support interpolated pulse shape (#31) close #26 --- .../InterpolatedShapeInfo.cs | 15 +++++ src/Qynit.PulseGen.Server/ShapeInfo.cs | 1 + src/Qynit.PulseGen/InterpolatedPulseShape.cs | 59 +++++++++++++++++++ src/Qynit.PulseGen/Qynit.PulseGen.csproj | 1 + src/Qynit.PulseGen/WaveformSampler.cs | 7 +-- 5 files changed, 77 insertions(+), 6 deletions(-) create mode 100644 src/Qynit.PulseGen.Server/InterpolatedShapeInfo.cs create mode 100644 src/Qynit.PulseGen/InterpolatedPulseShape.cs diff --git a/src/Qynit.PulseGen.Server/InterpolatedShapeInfo.cs b/src/Qynit.PulseGen.Server/InterpolatedShapeInfo.cs new file mode 100644 index 0000000..3cc4b71 --- /dev/null +++ b/src/Qynit.PulseGen.Server/InterpolatedShapeInfo.cs @@ -0,0 +1,15 @@ +using MessagePack; + +namespace Qynit.PulseGen.Server; + +[MessagePackObject] +public sealed record InterpolatedShapeInfo( + [property: Key(0)] double[] X, + [property: Key(1)] double[] Y) : ShapeInfo +{ + private InterpolatedPulseShape? _pulseShape; + public override IPulseShape GetPulseShape() + { + return _pulseShape ??= InterpolatedPulseShape.CreateFromXY(X, Y); + } +} diff --git a/src/Qynit.PulseGen.Server/ShapeInfo.cs b/src/Qynit.PulseGen.Server/ShapeInfo.cs index 2bba29f..eb48158 100644 --- a/src/Qynit.PulseGen.Server/ShapeInfo.cs +++ b/src/Qynit.PulseGen.Server/ShapeInfo.cs @@ -4,6 +4,7 @@ namespace Qynit.PulseGen.Server; [Union(0, typeof(HannShapeInfo))] [Union(1, typeof(TriangleShapeInfo))] +[Union(2, typeof(InterpolatedShapeInfo))] public abstract record ShapeInfo { public abstract IPulseShape GetPulseShape(); diff --git a/src/Qynit.PulseGen/InterpolatedPulseShape.cs b/src/Qynit.PulseGen/InterpolatedPulseShape.cs new file mode 100644 index 0000000..e60bd44 --- /dev/null +++ b/src/Qynit.PulseGen/InterpolatedPulseShape.cs @@ -0,0 +1,59 @@ +using System.Numerics; + +using BitFaster.Caching.Lru; + +using CommunityToolkit.Diagnostics; + +using MathNet.Numerics; +using MathNet.Numerics.Interpolation; + +namespace Qynit.PulseGen; + +public sealed record InterpolatedPulseShape(IInterpolation Interpolation) : IPulseShape +{ + public IqPair SampleAt(T x) where T : unmanaged, IFloatingPointIeee754 + { + var half = T.CreateChecked(0.5); + return (x >= -half && x <= half) + ? T.CreateChecked(Interpolation.Interpolate(double.CreateChecked(x))) + : T.Zero; + } + + public static InterpolatedPulseShape CreateFromXY(IReadOnlyList x, IReadOnlyList y) + { + if (x.Count != y.Count) + { + ThrowHelper.ThrowArgumentException("x and y must have the same length."); + } + var key = (new ValueArray(x), new ValueArray(y)); + return Cache.GetOrAdd(key, k => + { + var interpolation = Interpolate.RationalWithoutPoles(x, y); + return new InterpolatedPulseShape(interpolation); + }); + } + + private readonly record struct ValueArray + { + public T[] Data { get; init; } + public ValueArray(IEnumerable values) + { + Data = values.ToArray(); + } + public bool Equals(ValueArray other) + { + return Data.SequenceEqual(other.Data); + } + public override int GetHashCode() + { + var hash = new HashCode(); + foreach (var item in Data) + { + hash.Add(item); + } + return hash.ToHashCode(); + } + } + + private static readonly FastConcurrentLru<(ValueArray, ValueArray), InterpolatedPulseShape> Cache = new(666); +} diff --git a/src/Qynit.PulseGen/Qynit.PulseGen.csproj b/src/Qynit.PulseGen/Qynit.PulseGen.csproj index 68f9bf6..5ce613a 100644 --- a/src/Qynit.PulseGen/Qynit.PulseGen.csproj +++ b/src/Qynit.PulseGen/Qynit.PulseGen.csproj @@ -9,6 +9,7 @@ + diff --git a/src/Qynit.PulseGen/WaveformSampler.cs b/src/Qynit.PulseGen/WaveformSampler.cs index 4fa959a..6ffb852 100644 --- a/src/Qynit.PulseGen/WaveformSampler.cs +++ b/src/Qynit.PulseGen/WaveformSampler.cs @@ -9,12 +9,7 @@ public static class WaveformSampler { private const int PlateauThreshold = 128; - private static readonly FastConcurrentLru> MemoryCache; - - static WaveformSampler() - { - MemoryCache = new FastConcurrentLru>(666); - } + private static readonly FastConcurrentLru> MemoryCache = new(666); public static EnvelopeSample? GetEnvelopeSample(EnvelopeInfo envelopeInfo, Envelope envelope) {