RX channels alignment

Is it possible to maitain channel alignment between channels A and B? It seems that there is time shift between channels (it can be seen as linear phase difference). From what i experienced it is connected with decimation block. Depending on decimation ratio the time shift has different “resolution”. For example if decimation ratio is 8 then time misalignment occurs in multiples 1/8th of output sample time Ts. If decimation ratio is 16 te misalignment is in 1/16th of Ts. It seems that counter within decimators are not aligned. There are two different registers controlling decimation for each channel therefore it is not possible to write both simultaneously. The misalignment is always within ± 1 Ts.

It is possible to write registers to both A and B channels simultaneously.
0x0020[1:0] MAC - parameter controls which channel is active for write/read:
0 - both channels disabled
1 - channel A
2 - channel B
3 - both A&B channels active, usable only for writing. Reading attempts will return undefined result.

Or you could try after setting decimations for both channels to reset their RxTSP block logics.
These two bits can be toggled simultaneously by single register write
0x0020[9] LRST_RX_A - Resets all the logic registers to the default state for Rx MIMO channel A
0x0020[11] LRST_RX_B - Resets all the logic registers to the default state for Rx MIMO channel B

Sounds good doesn’t work unfortunately.
I tried different approaches. Using resets powerdown and simultaneous write to both registers. I could not obtain repeatable results.
Maybe LimeSDR team would join the discussion? Any hints?

points at ricardas above you already have.

Try:

  1. Disable clock generator, set EN_G_CGEN 0x0086[0]=0
  2. Reset RxTSP logics by toggling(1->0->1) 0x0020[9] LRST_RX_A, 0x0020[11] LRST_RX_B
  3. Enable clock generator, set EN_G_CGEN 0x0086[0]=1

Still no luck. We’re so close to obtain full coherency. Without synchronization it is hard to make more accurate VNA(one measuring transmitted and reflected wave).

Hello @modimo,

What software are you using?

I am using SoapySDR C++ api with my own application. I to write to LMS I had to patch SoapyLMS7::transactSPI method in order to be able to write to registers.

Hi @modimo,

Do you mind to share patched SoapyLMS7::transactSPI function and a code snippet where you change the registers Ricardas is talking about.

I don’t have access to exact sources right now. Here are my routines as i remember them.

In limesuite SoapyLMS7/Settings.cpp

unsigned SoapyLMS7::transactSPI(const int addr, const unsigned data, const size_t /*numBits*/)
{
    uint32_t input = data;
    uint32_t readback = 0;
    int st;
	if((addr>>15)&1)//write
		st	= _conn->TransactSPI(addr, &input, 0, 1);
	else
		st	= _conn->TransactSPI(addr, &input, &readback, 1);
	
	
    if (st != 0) throw std::runtime_error(
        "SoapyLMS7::transactSPI("+std::to_string(addr)+") FAIL");
    return readback;
}

In my code

void MyClass::writeReg(int addr, int data){
	device->transactSPI(addr|(1<<15),data,0);
}

int MyClass::readReg(int addr){
	int ret=device->transactSPI(addr,0,0);
	return ret;
}

void MyClass::alignChannels(){
int reg=0;
//1. Disable clock generator, set EN_G_CGEN 0x0086[0]=0
reg=readReg(0x86);
reg&=~(1<<0);
writeReg(0x86,reg);
//2. Reset RxTSP logics by toggling(1->0->1) 0x0020[9] LRST_RX_A, 0x0020[11] LRST_RX_B
reg=readReg(0x20);
reg&=~((1<<9)|(1<<11));
writeReg(0x20,reg);
reg|=((1<<9)|(1<<11));
writeReg(0x20,reg);
//3. Enable clock generator, set EN_G_CGEN 0x0086[0]=1
reg=readReg(0x86);
reg|=(1<<0);
writeReg(0x86,reg);
}

I will post original sources later today. Reading and writting to registers works correctly.

Hi @modimo,

OK, will wait for an updated code.
Meanwhile could you explain how do you measure alignment between channels A and B, please.

I transmit chirp signal using TX1. Then I split this signal using simple resistive power splitter and apply it to RX1_L and RX2_L(cable length the same). With received signal from RX1 and RX2 I calculate Fourier transform RX1_FFT and RX2_FFT. Then I divide bin-by-bin RX2_FFT/RX1_FFT. Argument of this ratio represent phase shift between channels for given frequency. For aligned channels I expect them to be flat and linear. When there is one sample delay there is slope of 2piTs radians/Hz where Ts is sample time in seconds. With half-sample delay the slope is 2piTs/2 radians/Hz etc.
I discovered this trying to implement fast VNA using dual directional coupler. Phase discontinuities have led me to this effect.

2 Likes

Updated code.

uint16_t MainWindow::readRegister(uint16_t addr){
    uint16_t ret=sdrDevice->transactSPI(LMS7002M_SPI_INDEX,addr<<16,0);
    return ret;
}

void MainWindow::writeRegister(uint16_t addr,uint16_t reg){
    sdrDevice->transactSPI(LMS7002M_SPI_INDEX,(1<<31)|addr<<16|reg,0);
}

uint16_t MainWindow::dispRegister(uint16_t addr){
    uint16_t ret=readRegister(addr);
    qDebug()<<"Reg: "<<QString("%1").arg(addr, 4, 16, QChar('0'))<<
              " Val: "<<QString("%1").arg(ret, 4, 16, QChar('0'));
    return ret;
    
}

void MainWindow::testButton(){
    uint16_t addr=0x20;
    uint16_t regorig=0;
    uint16_t reg=0;
    uint16_t reg400;//=dispRegister(0x11c);

    
    //1. Disable clock generator, set EN_G_CGEN 0x0086[0]=0
    reg=dispRegister(0x86);
    reg&=~(1<<0);
    writeRegister(0x86,reg);
    dispRegister(0x86);
    //2. Reset RxTSP logics by toggling(1->0->1) 0x0020[9] LRST_RX_A, 0x0020[11] LRST_RX_B
    reg=dispRegister(0x20);
    reg&=~((1<<4)|(1<<5)|(1<<9)|(1<<11));
    writeRegister(0x20,reg);
    dispRegister(0x20);
    reg|=((1<<4)|(1<<5)|(1<<9)|(1<<11));
    writeRegister(0x20,reg);
    dispRegister(0x20);
    //3. Enable clock generator, set EN_G_CGEN 0x0086[0]=1
    reg=dispRegister(0x86);
    reg|=(1<<0);
    writeRegister(0x86,reg);
    usleep(100000);
    dispRegister(0x86);
    
}

Did you ever do a steady-state measurement with your system? I have found that phase is stable over a very short time, but shifts wildly over a longer period (30 seconds or more) which is trouble for me as the phase difference between the two channels shifts off of a calibrated value.

Did you end up getting the sample alignment dealt with?

I did not notice phase drifting over time. How did you calibrate phase shift?

Supposedly you can adjust phase alignment between the RX channels, however if the phase shift between the two drifts (over 180 degrees in 30 seconds in my case) constantly then static calibration isn’t going to do a lot unless you’re doing it constantly. I imagine this would look something like:

loopback RX to TX
RX and TX LO common
TX calibrating signal
Adjust RX phase shift
TX off, RX back to ANT ports
Measure.