Livt packages
Livt.Signal
Version 0.1.1
Q1.15 sample streams, filters, windows, rate conversion, FFTs, oscillators, and mixers for Livt.
Published files (80)
src/oscillator/CordicNcoQ15.lvt
namespace Livt.Signal.Oscillator
using Livt.Math.Trigonometry
using Livt.Signal.Transform
/**
* Generates an unframed complex Q1.15 oscillator with a resource-shared CORDIC.
* The unsigned PHASE_BITS accumulator represents one complete turn modulo
* 2^PHASE_BITS. It advances by phaseIncrement only when an output token is
* accepted, so downstream stalls preserve oscillator/sample coherence.
*/
component CordicNcoQ15<PHASE_BITS: int = 32, INITIAL_PHASE: int = 0>
{
static assert PHASE_BITS >= 16 && PHASE_BITS <= 32,
"CORDIC NCO phase width must be in 16..32"
public const OUTPUT_LANES: int = 1
public const CORDIC_ITERATIONS: int = 16
public const MAX_ERROR_LSB: int = 4
outputStream: IComplexSampleStream<logic[16]>
cordic: CordicSinCosQ15
accumulator: logic[PHASE_BITS]
/**
* Runtime frequency-control word in modulo-turn phase units per sample.
*/
public phaseIncrement: in logic[PHASE_BITS]
/**
* Phase associated with the currently offered or next computed sample.
*/
public phase: out logic[PHASE_BITS]
/**
* Binds the oscillator output to a borrowed producer endpoint.
*/
new(outputStream: flip IComplexSampleStream<logic[16]>)
{
this.outputStream = outputStream
cordic = new CordicSinCosQ15()
accumulator = INITIAL_PHASE as logic[PHASE_BITS]
}
/**
* Exposes the modulo phase without introducing another state owner.
*/
process Observe[]()
{
phase = accumulator
}
/**
* Computes and offers one oscillator token at a time.
*/
process Generate()
{
state Calculate {
var phaseQ15 = accumulator[PHASE_BITS - 16: PHASE_BITS] as int
cordic.Compute(phaseQ15)
outputStream.real = cordic.GetCos() as logic[16]
outputStream.imag = cordic.GetSin() as logic[16]
outputStream.valid = true
outputStream.first = false
outputStream.last = false
goto Offer
}
state Offer {
if (outputStream.ready) {
outputStream.valid = false
accumulator = ((accumulator as uint)
+ (phaseIncrement as uint)) as logic[PHASE_BITS]
goto Advance
}
}
state Advance {
// Allow the owned accumulator update to become visible before
// slicing the phase for the next serialized CORDIC request.
goto Calculate
}
}
}