mirror of
https://github.com/DSheirer/sdrtrunk.git
synced 2026-11-13 17:17:29 -05:00
2537 Complex Vector Oscillator (256/512) Lanes Can Drift Apart Over Time (#2538)
* #2535 Heterodyne Channelizer enhancements and corrections. * #2537 Complex vector oscillator SIMD lane drift. Realigns the SIMD lanes every 262,144 samples. At frequencies where the rotation for a set of lanes is nearly a whole or half turn, rounding affects each lane differently and the lanes drift apart until the next frequency change, producing spurs at multiples of the sample rate divided by the lane count. Lane phase error at 3125 Hz with a 50 kHz sample rate was about -38 dBc after one hour and is now about -83 dBc with 16 lanes and -73 dBc with 8 lanes. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> * #2537 test updates * #2537 test updates --------- Co-authored-by: denny <dennis.sheirer@gmail.com> Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
114
src/main/java/io/github/dsheirer/buffer/SharedNativeBuffer.java
Normal file
114
src/main/java/io/github/dsheirer/buffer/SharedNativeBuffer.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* *****************************************************************************
|
||||
* Copyright (C) 2014-2023 Dennis Sheirer
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>
|
||||
* ****************************************************************************
|
||||
*/
|
||||
package io.github.dsheirer.buffer;
|
||||
|
||||
import io.github.dsheirer.sample.complex.ComplexSamples;
|
||||
import io.github.dsheirer.sample.complex.InterleavedComplexSamples;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.NoSuchElementException;
|
||||
|
||||
/**
|
||||
* Native buffer wrapper that lets multiple channels share one conversion of the native samples. Each channel's
|
||||
* iterator returns the same complex samples instances, on the channel's own thread, so consumers must not modify the
|
||||
* samples. The converted samples are released when the channels release this wrapper.
|
||||
*/
|
||||
public class SharedNativeBuffer implements INativeBuffer
|
||||
{
|
||||
private final INativeBuffer mNativeBuffer;
|
||||
private final List<ComplexSamples> mConverted = new ArrayList<>();
|
||||
private Iterator<ComplexSamples> mConverter;
|
||||
|
||||
/**
|
||||
* Constructs an instance
|
||||
* @param nativeBuffer to convert
|
||||
*/
|
||||
public SharedNativeBuffer(INativeBuffer nativeBuffer)
|
||||
{
|
||||
mNativeBuffer = nativeBuffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates if the converted samples include the index, converting the next samples as needed.
|
||||
*/
|
||||
private synchronized boolean hasConverted(int index)
|
||||
{
|
||||
if(mConverter == null)
|
||||
{
|
||||
mConverter = mNativeBuffer.iterator();
|
||||
}
|
||||
|
||||
if(index == mConverted.size() && mConverter.hasNext())
|
||||
{
|
||||
mConverted.add(mConverter.next());
|
||||
}
|
||||
|
||||
return index < mConverted.size();
|
||||
}
|
||||
|
||||
private synchronized ComplexSamples getConverted(int index)
|
||||
{
|
||||
return mConverted.get(index);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<ComplexSamples> iterator()
|
||||
{
|
||||
return new Iterator<>()
|
||||
{
|
||||
private int mIndex = 0;
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return hasConverted(mIndex);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ComplexSamples next()
|
||||
{
|
||||
if(!hasNext())
|
||||
{
|
||||
throw new NoSuchElementException("No more samples");
|
||||
}
|
||||
|
||||
return getConverted(mIndex++);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterator<InterleavedComplexSamples> iteratorInterleaved()
|
||||
{
|
||||
return mNativeBuffer.iteratorInterleaved();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int sampleCount()
|
||||
{
|
||||
return mNativeBuffer.sampleCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp()
|
||||
{
|
||||
return mNativeBuffer.getTimestamp();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user