Page 1 of 3
Posted: Fri Mar 23, 2018 8:26 pm
I have an application that needs I/Q data at 192 kHz. The lowest that the RSP's go is 500 kHz. I don't need any FFT or demodulation - I just need 192 kHz I/Q. Resampling ? Suggestions on how to do this in software ?
Posted: Sat Mar 24, 2018 7:25 am
You should be able to achieve an effective sampling rate of 192KHz by using a sampling rate of 3.072MHZ and a decimation factor of 16.
I've attached an example (StreamingSample_2.zip) with source code, that allows you to play around with various sampling rates and decimation factors. It's based on a simple application I put together some time ago to demonstrate how to interface to the SDR API DLL (mir_sdr_api.dll) from C# in Visual Studio 2017. The source code has been modified and now allows RX frequency, sampling rate and decimation factors to be set. It's not bullet-proof and there little sanity checking in the code.
The API DLL is not included in the zip file. The project's properties are set for 32 bit, and you will need to place a copy of the 32 bit version of mir_sdr_api.dll in the same directory as the source code.
The API DLL accepts a sampling rate of 3.072MHz without returning an error so I must assume it does actually sample at that frequency. The DLL function that sets the decimation factor (mir_sdr_DecimateControl) should only be fed with factors of 2, 4, 8, 16, 32 or 64 (The API documentation is ambiguous here as one part says max of 32, another part says 64) - but seems to accept whatever is given to it without returning an error.
For anyone who may be interested, I have included a C# wrapper in the zip file for the mir_sdr_api.dll. The wrapper is SDRInterface.cs and includes support for the RSP1A and has additional enums to eliminate "magic numbers" in source code. I only have an RSPII so have been unable to test it with other hardware versions. Any feedback will be gratefully received.
Good luck and let us all know how it goes...
Please note: File has been removed due to coding error. Correct code may be downloaded in post further down this thread. Apologies to anyone who downloaded the code and found decimation was not working as expected. Corrected zip file is StreamingSample_3.zip.
Posted: Sat Mar 24, 2018 3:02 pm
Thanks for the code - that is a huge help.
A few questions/comments for you and/or the SDRPlay team:
- When in the LowIF mode, why can't the decimation be user specified ? The man page says: "Also for IQ output in Low IF mode, enable must = 0 as the decimation is automatic within the API." Using the Zero IF mode results in a center frequency bump/leakage that a problem in my application.
- It would be nice if the ExtIO allowed as much flexibility as the API (or make the current ExtIO source public ?).
Posted: Sun Mar 25, 2018 4:42 am
I'm afraid I can't help you there. Maybe someone from tech support could explain the reasons. I did see an early version of the source code for EXTIO.dll on GitHub some time ago - https://github.com/SDRplay/ExtIO_SDRplay
. I don't know if it's still there though, as it used mir_sdr_Init (now deprecated) instead of mir_sdr_StreamInit. Yes, source code for the current version would be handy.
In the meantime, I've found a small problem with the code I posted yesterday. Reading through the API documentation again (RTFM always pays) I saw that streaming must be started before a decimation factor is set. In my code I set a decimation factor before starting the stream.
mir_sdr_DecimateControl returns mir_sdr_Success even if an incorrect value is passed. An incorrect value disables decimation. I assumed that all was well when I got an mir_sdr_Success return. The function does return an mir_sdr_OutOfRange error if the decimation value is too high. I would have thought it would also return an mir_sdr_InvalidParam or mir_sdr_NotInitialised error. Maybe something for the tech guys to note for future updates ?
In the meantime, I've changed the code so that streaming is started before setting a decimation factor. In addition, I've added some very basic sanity checks, and another function that reports any errors to the console, along with a brief description of the error. The revised code is attached here as StreamingSample_3.zip. Apologies to anybody who has already downloaded StreamingSample_2.zip and found that decimation is not working as expected.
All the best...
Posted: Sun Mar 25, 2018 6:37 am
Higher levels of decimation were originally introduced to allow the framing of specific bands in SDRuno. This is achieved by setting specific combinations of sample rate and decimation and is currently only achievable in Zero IF mode, because it is only in ZIF mode that it is possible to arbitrarily set the sample rate anywhere between 2 and 10 MHz. In low IF mode, because it is an IF that is being sampled, there is a much greater restriction on the allowable sample rates that can be used for reasons of aliasing and because the sample rate has to be fixed to specific values to allow an efficient direct digital down-conversion (DDC) scheme to be implemented. These restrictions exist within the API and not the ExtIO plugin.
The ExtIO does place a restriction on the decimation level for certain historical reasons and that is that the final sample rate should always be greater or equal to the analogue IF bandwidth to minimise spurious imaging as a result of historical limitations in the decimation filtering.
So in a nutshell, the limitations are partly legacy and partly due to the architecture of the API and partly due to physical restrictions required for anti-aliasing purposes.
Now the good news is that we are looking to re-architecture the API and incorporate fractional re-sampling. This will give a much higher level of flexibility in the final sample rate that can be achieved in low IF mode, but at this stage, I cannot at this stage be certain whether it will give you the precise sample rate that you are looking for. I am also unable to say specifically when this work will be completed, but it is likely to be within the next 2-3 months as this is just part of a general upgrade and re-structuring of the API.
Posted: Sun Mar 25, 2018 1:30 pm
I noticed the reversed StreamInit/Decimate function calls, but thought it might actually be correct. Once you call StreamInit, it's off to the races - the API immediately starts sending samples, probably with decimation = 1. Can you really change the decimation at this point ?
This is another case where it would really be helpful if the SDRPlay team would share their current ExtIO, or at least a psuedo-code version, so we could see what the experts are doing.
Posted: Sun Mar 25, 2018 11:38 pm
I had a look at Steve's code and it all looks correct to me. What is the concern? StreamInit starts a thread that sends samples to the stream callback. Subsequent commands communicate to that thread to make any changes.
Also, if you look you will see that Steve's code sets the decimation parameters before StreamInit using DecimateControl, but that could equally be set after StreamInit.
Posted: Mon Mar 26, 2018 1:10 am
Thanks for the response.
My concern is that streamcbfunc is going to start receiving I/Q samples before mir_sdr_DecimateControl has been acted upon by the API. Therefore, the upstream user of the I/Q samples doesn't know when the samples reflect the requested sampling frequency/decimation factor. So, the safe thing to do would be to throw away the samples for some time period after mir_sdr_DecimateControl has been called.
Steve L (not to be confused with the other Steve in this thread !)
Posted: Mon Mar 26, 2018 2:38 am
Hi Steve, and Tech Support
The first version of the code I posted set decimation before starting the stream, and that seems to be the version Support is referring to.The API documentation for mir_sdr_DecimateControl states:
"Note: Requires internal stream thread to have been created via mir_sdr_StreamInit() for decimation to be enabled. Also for IQ output in Low IF mode, enable must = 0 as the decimation is automatic within the API."
The above quote seems a bit ambiguous. I read this as meaning the stream must be started before setting a decimation factor, perhaps I have misinterpreted it. Anyway, I played it safe and changed the code to set decimation after the stream was started, even though the return from mir_sdr_DecimationControl indicated success if decimation was set prior to starting the stream. Looking at the sample code at the end of the API document, I see that decimation is set prior to starting the stream, although the parameters passed actually disables decimation. As noted in the code, written for information purposes only.
Many of the API functions require the stream to be started before being called, otherwise they will return an mir_sdr_NotInitialised error. This should not cause a problem. In a project I am currently working on, I make many calls to the API, particularly RX frequency, sampling rate and decimation factor. I just set a notReady flag that is the first thing checked in the stream callback function, the function returning without doing anything until the flag is cleared once settings have been changed and everything has settled down. For example, changing RX frequency can take several milliseconds, and up to 100 milliseconds if a band boundary is crossed.
I guess it's a matter of trying it either way and see what works for you, easy enough to change it it doesn't work as expected. Perhaps the next version of the API doc should be titled: "Software Defined Radio API - A Tale of Mystery and Intrigue" - Only joking
- Believe me, over the years I've seen far worse from multinational companies that have dedicated documentation divisions.
Posted: Mon Mar 26, 2018 7:24 am
DecimateControl can be used before or after StreamInit. In the current version of the API, decimation is only really useful for Zero IF mode. In Low IF mode, the de-rotation and filtering to produce an IQ output only occurs in the specific instances specified in the mir_sdr_DownConvert section otherwise you will just get data from the I channel and then need to make additional calls to mir_sdr_DownConvert, etc.
The approach with the API is to allow it to control all aspects of the hardware. This produces a complex specification. If developers aren't sure about whether they are controlling the hardware correctly, they can always send us sample code to check with any concerns.
Low IF mode will be made easier to use and more flexible for developers in future revisions of the API, as has already been mentioned above.