Skip to content

Commit

Permalink
feat: ✨ support interpolated pulse shape (#31)
Browse files Browse the repository at this point in the history
close #26
  • Loading branch information
kahojyun authored Jul 7, 2023
1 parent 73b058c commit 7772db3
Show file tree
Hide file tree
Showing 5 changed files with 77 additions and 6 deletions.
15 changes: 15 additions & 0 deletions src/Qynit.PulseGen.Server/InterpolatedShapeInfo.cs
Original file line number Diff line number Diff line change
@@ -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);
}
}
1 change: 1 addition & 0 deletions src/Qynit.PulseGen.Server/ShapeInfo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
59 changes: 59 additions & 0 deletions src/Qynit.PulseGen/InterpolatedPulseShape.cs
Original file line number Diff line number Diff line change
@@ -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<T> SampleAt<T>(T x) where T : unmanaged, IFloatingPointIeee754<T>
{
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<double> x, IReadOnlyList<double> y)
{
if (x.Count != y.Count)
{
ThrowHelper.ThrowArgumentException("x and y must have the same length.");
}
var key = (new ValueArray<double>(x), new ValueArray<double>(y));
return Cache.GetOrAdd(key, k =>
{
var interpolation = Interpolate.RationalWithoutPoles(x, y);
return new InterpolatedPulseShape(interpolation);
});
}

private readonly record struct ValueArray<T>
{
public T[] Data { get; init; }
public ValueArray(IEnumerable<T> values)
{
Data = values.ToArray();
}
public bool Equals(ValueArray<T> 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<double>, ValueArray<double>), InterpolatedPulseShape> Cache = new(666);
}
1 change: 1 addition & 0 deletions src/Qynit.PulseGen/Qynit.PulseGen.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
<ItemGroup>
<PackageReference Include="BitFaster.Caching" Version="2.2.0" />
<PackageReference Include="CommunityToolkit.Diagnostics" Version="8.2.0" />
<PackageReference Include="MathNet.Numerics" Version="5.0.0" />
<PackageReference Include="QuikGraph" Version="2.5.0" />
</ItemGroup>

Expand Down
7 changes: 1 addition & 6 deletions src/Qynit.PulseGen/WaveformSampler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,7 @@ public static class WaveformSampler<T>
{
private const int PlateauThreshold = 128;

private static readonly FastConcurrentLru<EnvelopeCacheKey, EnvelopeSample<T>> MemoryCache;

static WaveformSampler()
{
MemoryCache = new FastConcurrentLru<EnvelopeCacheKey, EnvelopeSample<T>>(666);
}
private static readonly FastConcurrentLru<EnvelopeCacheKey, EnvelopeSample<T>> MemoryCache = new(666);

public static EnvelopeSample<T>? GetEnvelopeSample(EnvelopeInfo envelopeInfo, Envelope envelope)
{
Expand Down

0 comments on commit 7772db3

Please sign in to comment.