[USRP-users] Exact alignment between gnuradio sample stream and USRP time

Marcus D. Leech patchvonbraun at gmail.com
Mon Jan 27 18:44:02 EST 2020


On 01/27/2020 05:34 PM, Lukas Haase wrote:
>> Gesendet: Freitag, 24. Januar 2020 um 11:53 Uhr
>> Von: "Marcus D. Leech" <patchvonbraun at gmail.com>
>> An: "Lukas Haase" <lukashaase at gmx.at>
>> Cc: usrp-users at lists.ettus.com
>> Betreff: Re: [USRP-users] Exact alignment between gnuradio sample stream and USRP time
>>
>> On 01/24/2020 02:57 AM, Lukas Haase wrote:
>>>> On 01/23/2020 12:32 PM, Lukas Haase via USRP-users wrote:
>>>>> Hi,
>>>>>
>>>>> TO MY UNDERSTANDING, the USRP has an internal clock that is different from host clock when running gnuradio (which makes sense because there are buffers etc in between).
>>>>> Example: I transmit a CW at f=1001, receive it at f=1000 and then use gnuradio to downconvert the remaining 1 MHz I run into trouble (tried it...).
>>>>>
>>>>> For this reason, there exist timed commands and the tune_request object with which I can execute commands (LO tuning) at a precice time. For example, with these commands I can phase align tuning between TX/RX at different center frequencies:
>>>>>
>>>>>      tune_req_tx = uhd.tune_request(fcenter-1e6, 1e6)
>>>>>      tune_req_rx = uhd.tune_request(2*fcenter)
>>>>>      tune_req_rx.args=uhd.device_addr(','.join(["mode_n=integer", "int_n_step=1000e3",]))
>>>>>      tune_req_tx.args=uhd.device_addr(','.join(["mode_n=integer", "int_n_step=1000e3",]))
>>>>>
>>>>>      now = self.uhd_usrp_sink_0.get_time_now()
>>>>>      self.uhd_usrp_sink_0.set_command_time(now + uhd.time_spec(0.1))
>>>>>      self.uhd_usrp_source_0.set_command_time(now + uhd.time_spec(0.1))
>>>>>
>>>>>      self.uhd_usrp_sink_0.set_center_freq(  tune_req_tx, 0)
>>>>>      self.uhd_usrp_source_0.set_center_freq(tune_req_rx, 0)
>>>>>
>>>>>      self.uhd_usrp_source_0.clear_command_time()
>>>>>      self.uhd_usrp_sink_0.clear_command_time()
>>>>>
>>>>> The commands execute execatly at get_time_now() plus 100ms. As far as I understand, these 100ms are to ensure that the host computer has enough time until the USRP processes the clear_command_time function. But it does not relate the exact point in time with anything that exists in gnuradio.
>>>>>
>>>>> MY QUESTION: What I am unsure is how to align samples in gnuradio with the time on the USRP. For example, suppose I have an ideal clock signal in gnuradio and I want to perform a timed command EXACTLY at a particular sampling point (e.g. rising edge). How would I go about this?
>>>>>
>>>>> The actions I want to execute exactly time aligned with gnuradio include: tuning requests, reading out sensors (PLL sensor when it settled), switching IO pins through the GPIO interface.
>>>>> For example, I would like to switch a GPIO port exactly once per period of a signal in gnuradio and exactly at the same time (clearly there will be delays but that's OK as long as the delay is fixed).
>>>>> As another example, I would like to re-tune exactly once in every period of a gnuradio signal. Then I would like to read out when the PLL has settled and generate a binary indicator signal out of it. Plotting the original signal and the indicator signal should tell me exactly (at least sample accuracy) how long the PLL took to settle *relative* to the signal in gnuradio.
>>>>>
>>>>>
>>>>> Thank you very much,
>>>>> Luke
>>>> Whatever "dance" you're using to set the USRP time, (presumably
>>>> something like set_time_unknown_pps), you need to have it derive the
>>>>      USRP time register from the host time.  The normal code that is
>>>> emitted in GRC for "unknown_pps" just resets the USRP time to zero.
>>>>      But you can arrange for it to be the host time (+1 second or
>>>> something) instead.
>>>>
>>>> You haven't indicated whether you're using GRC, or "naked" Gnu Radio
>>>> programming.
>>>>
>>>> General synchronization "things" are discussed in the knowledge base, here:
>>>>
>>>> https://kb.ettus.com/Synchronization_and_MIMO_Capability_with_USRP_Devices
>>> Hi Marcus,
>>>
>>> Thanks. I went through this page a few times and got synchronization between TX/RX (somewhat) running.
>>>
>>> I am using GRC but willing to go "naked" where necessary (my main application will still always be grc+GUI).
>>>
>>> I guess I still don't understand what exactly what the "USRP time" is and how it related to sample time.
>>>
>>> I do not think it makes sense to lock the USRP time to the host time because the host time is independent from the sample time on the host (in gnuradio). Samples are buffered and depending on CPU load, samples may occur earlier or later than expected by CPU time. Say I generate the signal x[n] and the sample rate is 1kS/s, then in a real-time system I can expect each sample to occur exactly every ms. But on my host with gnuradio this is certainly not the case! x[1000] does not necessarily occur 1 seconds (in CPU time) after x[0].
>>>
>>> Again, what I want is I generate x[n] in gnuradio. For every, say, (n mod 1000)==0 I want to execute something on the USRP, for example flipping a GPIO which increases the gain of an amplifier ... exactly at the time when the *USRP* processes this sample. Not the host! Because the USRP, to my understanding, is like a realtime system.
>>>
>>> Now say the output of the amplifier is fed again into the USRP RX port and I read it back as y[n] from USRP Source.
>>>
>>> I will see the effect of the gain change in y[n] ... many samples after I did the request due to latency. But I want that the relative sample difference between x[n] and y[n] is always constant!
>>>
>>> Example:
>>>
>>> At x[0]    --> change gain to 1 --> at y[523]  I see gain changes to 1
>>> At x[1000] --> change gain to 2 --> at y[1523] I see gain changes to 2
>>> At x[2000] --> change gain to 3 --> at y[2523] I see gain changes to 3
>>>       ....
>>>
>>> I hope this example makes it more clear what I mean.
>>>
>>> This is just a toy example; in reality I would build x[n] in gnuradio to be a control signal that aligns all the actions in a predicable manner.
>>>
>>> Thanks,
>>> Luke
>>>
>> Sample streams from the USRP are time-stamped.  In Gnu Radio, that
>> generates a tag when the stream starts, and whenever there's an
>>    overrun.
>>
>> In the absence of overruns, you know exactly the sample time from
>> knowing the initial time-stamp, and simply counting samples, since
>>     the sample-rate is known, and fixed.
>>
>> This is drifting squarely into "how do I do stuff in Gnu Radio", so
>> there's a better audience for that on the discuss-gnuradio mailng list.
>>
>> If this were my problem, I'd probably write a custom block that
>> "scheduled things", based on knowing the most recent time tag, and
>>     the current sample count since the most recent time-tag.
> Hi Marcus,
>
> Thanks, that's very useful. I get the idea now. For example, for a frequency hopping system, I would queue the commands for the *next* period using timed commands (and hope that host->USRP is fast enough to process them before the time occurs).
>
> But why does the USRP use seconds and fractional seconds (rather than integer cycles etc)? Can this really guarantee proper timing?
Internally within the FPGA, the time register is just a wide integer 
register, incremented at whatever the master clock rate is.  But the API
   presents this in a way that is more portable across different device 
types.


>
> I can first set the USRP command time to zero (at startup in gnuradio). When I have a signal source going into a "USRP Sink" with samp_rate = 1 MHz and I want to execute a variety of of commands exactly at every 10000 samples, how does my timed command look like? For example, within the work() function of a block I can convert any sample to an absolute sample number from start on (with nitems_read etc.). Would something like
>
>      def work(self, input_items, output_items):
>          // check if "current" sample is within this processing block
>          // is yes, set timed command for next period
>          if self.curSamp >= nitems_read && self.curSamp < nitems_read() + len(input_items[0]):
>             // Hope that 10000/samp_rate is enough time to successfully send commands
>             // from gnuradio/host to USRP?
>             set_command_time((self.curSamp+10000) / self.samp_rate)
>             // tune different RXes to different frequencies
>             // operate GPIO pins
>             // ...
>             clear_command_time()
>             self.curSamp = self.curSamp + 10000
>          return 0
>
> be what you are thinking of?
>
>
> Thanks,
> Luke
Yes, like that.    Provided the PLL can actually re-tune within that 
interval, etc.


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>




More information about the USRP-users mailing list