Simple diy SDR radio with Tayloe mixer and STM32 - Page 1
Forum section: electronics / projects

author: Yansi
author_rank: Super Contributor
timestamp: June 08, 2015, 11:15:42 am
content: Hi!I am planning to build and test a very simple SDR radio. Computing power in today's microcontrollers is awesome, so why not to test something a little different: Tha plan is the SDR to be zero-IF only (no waterfall, tuneable only by LO), using a well known Tayloe mixer. I'd like to tap MW and the lower part of SW band, no VHF or UHF stuff.I will base it around some readily available MCU kit, most probably some STM32-NUCLEO board. I don't want to design a dedicated board for the whole thing. Only a plugable "shield". Keep in mind, this is only a test concept, not a final product.The shield would include the Tayloe mixer, and some cheapass audio DAC I'll find in my drawer. The only circuitry missing is the clock source for the Tayloe mixer.It'd be nice to generate the 4f by the MCU intself, but that can be done only for small frequencies and still with miserable nonlinear tuning step. So what do you think I should use as a LO for this project? I need a variable frequency digital clock signal, in the range of let's say from 1MHz to 25MHz or such with a tuning step of ideally 10Hz or just about.What would you suggest to be the cheapest solution for the LO?Because of the frequency range for the LO and the small required tuning step, I have already thought about using a DDS chip like AD9850 with a squarer on its output. But the DDS chip is still a little pricey (but not a big deal if needed) compared to the rest of the circuitry and I don't really need the qualities of its sinewave output. Are there any DDS digital clock synthetisers? Or would you suggest completely another solution for the digital LO?If it will work, I will share the results with You, I think more people could be interested in this SDR stuff.For those interested, many literature about SDR can be found here:http://www.arrl.org/software-defined-radioAnd for FM (or phase in general) demodulation, I find this one very useful:http://www.hyperdynelabs.com/dspdude/papers/DigRadio_w_mathcad.pdfBut I am still missing similar docu for SSB signal decoding in zero-IF receivers. I will look into this later.Thank you for your helpY

author: Kalvin
author_rank: Super Contributor
timestamp: June 08, 2015, 12:07:26 pm
content: Cheap chinese DDS-module and use the square wave output?Sample the resulting I and Q signal by the ADC and run the I and Q signals through the digital Hilbert filter.Maybe you could even utilize the digital I and Q signals from the DDS and drive the analog switches directly, so you might need to use only 2*fc sampling signal. If the DDS contains a feature which allows one to adjust the phase difference between the I and Q outputs, one could possibly compensate any phase differences in the analog I and Q signals.I dunno. Page 9:http://cbjohn.com/aa0zz/IQProUsers/W6JL/W6JL.pdfEdit: The cheap AD9850 has only one output, max 125MHz. So, it is usable up to 30MHz, as the Tayloe mixer uses 4*fc frequency. The chips with I and Q outputs cost much more.

author: LukeW
author_rank: Frequent Contributor
timestamp: June 08, 2015, 01:13:28 pm
content: http://www.silabs.com/Support%20Documents/TechnicalDocs/Si5351-B.pdfSi5351, perhaps?

author: Yansi
author_rank: Super Contributor
timestamp: June 08, 2015, 01:35:36 pm
content: Thanks, will stick to the DDS as planned. The AD9850 has the squaring comparator inside as obvious, but I haven't looked closely enough that the slower ones also have onchip capability to produce square. The AD9834 seems to be the thing I was looking for.I won't use any modules. If I am going to design custom bord for the shield, there is no need to use these.I will study what the Hilbert filter is. I've already seen the name mentioned, but dunno what it is yet.For the MUX I will use the part Dan Tayloe used in his original design: PI3B3253Q. The price is reasonable and parameters of the MUX way beyond what can some HC4052 offer. I have seen the HC4052 used in many simple designs over the web. But I think it is not the right part to use. It is quite slower and the ON resistance is more than order of magnitude worse.Si5351: Wow, thats a nice one.I quite worried about its price, but it is the same or little less than the AD9834. I will also consider this part. Thanks!

author: Kleinstein
author_rank: Super Contributor
timestamp: June 08, 2015, 04:57:00 pm
content: Usually one advantage of SDR is, that there is no need for fine tuning of the LO. So I would go for a rather faster version of the STM32 and use its internal ADCs to sample at a faster rate (e.g. 500 kHz). Than a LO from the PWM output of the µC might be feasible.

author: mark03
author_rank: Frequent Contributor
timestamp: June 08, 2015, 05:55:07 pm
content: If you're not already familiar with the "Softrock" series of radio receiver kits, you should go have a look at their design for ideas on your front end and mixer.

author: Yansi
author_rank: Super Contributor
timestamp: June 08, 2015, 06:44:11 pm
content: If you try to divide the frequency yourself, you will quickly analyze, that this won't help. The divide ratio should be very low, the step is nonlinear (hyperbolic) and too coarse. There is not enough computing power on any STM32 to overcome this for smooth tuning to be achieved.I need precisely tuneable LO, because I want to start with the simpliest SDR software form - without the FFT. Without FFT I can't shift the IF of the software receiver. The advantage should be that I can use very low samplerate* of the I/Q signals and the software decoding would require very small computing power. (I hope I got that right from what I've studied already)*only to allow enough bandwidth for the single modulated channel of information I want to decode.You mean Softrock like this one?http://fivedash.com/resource/LiteIISchematic.pdfTheres only oscillator, the traditional 7474 counter, the "mux-mixer" and one unnecessarily fast (215MHz) OPamp (why?) "softrocked" down to only about 80kHz of bandwidth with its NFB. And of course there's an input bandpass filter, that I'll probably omit for the crudity of my experiment. I can always connect the filter to the input through the SMA/BNC/whatever it will have.I have a bigass three quarter of megawatt transmitter tower a few tens of kilometers far from where I live, commercial broadcast, MW, AM. Sure, this will be the first thing I'll try to tune in.The actual state of this cruel experiment is:AD9834 (already ordered some), 74ALVC74, PI3B3253 for the mixer and TS922 opamp for the output I/Q signals. All 3V3 powered.The mixer will be designed according to this Tayloe's publication, see page 6:http://www.norcalqrp.org/files/Tayloe_mixer_x3a.pdfand DC coupled to the two ADCs.I have already started to draw a first version of the schematic, nothing complicated yet.

author: mark03
author_rank: Frequent Contributor
timestamp: June 08, 2015, 07:12:48 pm
content: Quote from: Yansi on June 08, 2015, 06:44:11 pmI mention the softrock because those hobbyists have been doing more or less what you propose, except for processing the data in a PC instead of an MCU, for a number of years. No doubt there are deficiencies in the design, but it is cheap, easy to build, and proves that the Si570 (and now Si5351) have adequate performance as LOs. You're not going to get a simpler LO source than this unless you attempt to generate it inside your MCU, which, as you point out, is not workable. DDS is fine too, of course, but it seems unnecessarily complicated. You don't need sinusoids, just squares.The popularity of the softrock means that the particular bus switch (FSTxxxx) they used for the mixer is well proven.

author: janoc
author_rank: Super Contributor
timestamp: June 08, 2015, 07:21:46 pm
content: Get one of the Si5351 modules (e.g. from Adafruit) - cheaper than the AD9850 ones and it gives you 3 frequencies with TTL outputs instead of one. AD9850 is better if you need sinewave outputs, but that is not your case when using the Tayloe detector. SI5351 is a bit harder to program, though.Here is a good description:http://m0xpd.blogspot.fr/2014/10/si5351.htmlThe Softrock that was mentioned earlier comes in two versions - the basic one has a fixed crystal oscillator but there is also a VFO available for it using Si570. Unfortunately, that chip is quite expensive and difficult to obtain in small quantities. I have got mine together with Softrock II kit from the website.@Kleinstein - 500kHz LO from an STM32 DAC would really suck, because that would give you at best 125kHz sampling frequency (you divide by 4 to get the quadrature signals in a Tayloe detector). The DAC tops out at around 1MHz even with DMA, so that is pretty much useless for this application unless you are planning to receive only very low frequency signals - the downmixed baseband needs to "fit" into the bandwidth of the soundcard/ADC your are using to digitize the signals, so 500kHz LO is pointless.

author: tonyarkles
author_rank: Regular Contributor
timestamp: June 08, 2015, 07:27:57 pm
content: Quote from: Yansi on June 08, 2015, 06:44:11 pmBased on a quick glance at the circuit, it looks like those opamp circuits have a significant amount of gain. Likely the fast opamp is used to ensure that there's enough OL gain available across the whole bandwidth.

author: Kleinstein
author_rank: Super Contributor
timestamp: June 08, 2015, 07:30:19 pm
content: There should be at least some basic bandpass (lowpass) filtering, as the mixer also contains some signal at the higher harmonics.The STM32 should be fast enough to do frequency shift in software as well. There is no need for a full FFT, its just a Hilbert transformation or complex mixing in software. This only takes reading two tabulated sin/cos values and doing 4 multiplications and additions for each pair of samples. So this should even works in the MHz sampling rate range. So usually the ADCs are more the limiting factor. The FFT is needed to get something like waterfall diagrams, but not for just AM or FM decoding.Going to zero IF somewhat brings the SDR concept to absurdum, as this already fully decodes (at least AM and approximately FM) in hardware. The fun with SDR is to directly use IF data. With I/Q data the information can be in a rather low frequency range, possibly including 0 Hz, but there is no need to have it perfectly centered. So something odd like a 42 Hz IF is perfectly OK with SDR, if you have full I/Q data (including DC). Even with a DDS, you would still have a few Hz of residual difference / drift. So the software has to cope with that anyway, and compensating for a few Hz or a few 100 kHz (provided sampling is fast enough) is essentially the same algorithm.There was no intention to use a 500 kHz LO from the DAC. I though about using something like 500 kHz (or even 1 MHz) of sampling with the internal ADC instead of the souldcard. The LO could come from a PWM channel - thus in the 1-10 MHz range, but with very limited resolution, thus requiring a faster ADC. Still it can be tricky with divide by 4 - in come cases one can avoid this as well, using two PWM channels with phase shift.

author: Yansi
author_rank: Super Contributor
timestamp: June 08, 2015, 07:55:08 pm
content: tonyarkles, that might be. I haven't analysed the circuit any deeper than a few looks over it.janoc: Maybe next time. AD9834 already ordered. Easier to programme the DDS - I don't want to fiddle with the clock generator I don't know anything about, I'd like to fiddle with the software I/Q decoding. And the AD9834 pricepoint is almost the same as the Silabs thingy. (about USD4)I have only 1 major design issue in this cruel SDR: I have just the input of the mixer - and what to do with it? It is like this:http://q36.imgup.net/asfdasdass641b.pngwith the sampling caps on the other side. The resistor divider is for DC bias.I need to have a defined source impedance to supply the MUX input. Is there any easy discrete transistor solution to do the impedance match, like using an emitter folower to take the "undefined antenna input" and output the signal at some defined impedance, like 50 or 200 ohm? What would you suggest to use there? I don't do RF stuff regularly, sorry for my lack of knowledge there.Probably some small discrete amp/buffer with a defined output impedance, so I can calculate the gain of the mixer stage... ? The input frequencies would be 7MHz at best, so please avoid suggesting use of MAR5 or other similar monolithic amps.Kleinstein: I know, that the STM32 can do full FFT (probably?), already seen a lot of people doing their SDRs with waterfalls on STM32... But I'd like to start with something easier, which has at least some chance to work at least somehow.If it will work, I will continue the work, sure. Doing the Hilbert Xform or complex mixing or ... with the sampled IQ data is still possible with the same hardware I am designing now.

author: Yansi
author_rank: Super Contributor
timestamp: June 08, 2015, 09:04:35 pm
content: Aww man... .I just looked how the complex mixing works: Only multiplying the complex IQ signal with complex exponential exp(j*omega*t)Is it really just that easy? So only requiring a time accumulator variable and table for sine(cosine) ? Wow... thats nice! Thanks for the tip.By the way if I'd use the complex mixing technique for shifting the IF, and still needed to display the waterfall spectrum... does it really implicate that the FFT is calculated onyl in a slow manner, to get reasonable update rate on the display? That seems to be also another nice trick to conserve computing power.The only thing missing is some filtering (and probably decimation after the complex mixing too).. is it right?

author: Kleinstein
author_rank: Super Contributor
timestamp: June 08, 2015, 10:41:22 pm
content: The FFT for the waterfall diagrams can also use complex numbers so no need to do the complex mixing before that. The FFT is not that complicated either and only needs to be calculated for every buffer filled. So after something like 256-1024 samples an FFT is calculated and the result display. This is also only something like 10-20 multiplications per sample. Thus well doable in real time for an ARM, if the output is simple. For overlap and using a hamming window, one might decide to do the FFT twice as often, but usually no need to do it faster. With I/Q Data the FFT gives negative an positive frequencies as offset to the hardware LO.How output is handled depends on the type of modulation. In the simple AM case, one could use some kind of synchronous detector with carrier recovery: One simple way would be using a kind of PLL to recover the carrier (or IF of it) and really get the IF after digitally mixing the IF down 0, and have a fixed phase. For example the imaginary part is averaged and regulated to an average of 0 by feedback to the IF frequency used in software mixing. The real part is than directly the decoded AM signal and might just need filtering / decimation.There are other more advanced techniques too, especially if it comes to digitally coded signals in the short wave range. AM is getting fewer and fewer.A simple target might be a time signal. Usually modulation is rather simple.

author: Yansi
author_rank: Super Contributor
timestamp: June 08, 2015, 11:40:24 pm
content: Well, a litle confusion happening here, because from post to post you suggest completely different methods. I am fine with that, but I am trying to understandd them. So lets stick to this one, it is looking good enough for me.The IQ sampled data are then frequency offset (multiplication with the complex eponential), downsampled and filtered, demodulated. No FFT anywhere in the receiver chain. If I'd need to display the waterfall, I'd need to tap the sampled IQ data, fill a buffer, calculate FFT over this buffer, draw. But is there any need to compute it for every buffer fill? I think the only need for that is to keep the waterfall responsive enough to the input rate of change. If firing some serious sampling rate, I think there will be not enough computing power to calculate the FFT for every buffer fill.Sorry for the ugly drawing. :-)

author: mark03
author_rank: Frequent Contributor
timestamp: June 08, 2015, 11:57:15 pm
content: One small correction to your diagram, if you haven't already mixed the signal down to IF, you don't need two ADCs because you don't have I and Q yet. Instead, you just sample the  antenna with one ADC; the ADC data multiplied by cos(wt) you call "I" and the data multiplied by sin(wt) you call "Q". The google search term for this type of architecture is "direct sampling receiver"; see e.g. the OpenHPSDR Hermes project. The other trick you might like to look up is the "Cascaded Integrator Comb" filter, which is a very efficient low-pass filter for the decimator. Without something like a CIC you discover that the necessary low-pass filter is quite difficult to achieve with DSP, especially for a project like Hermes where they start at ~ 120 MSPS out of the ADC. (In fact, at those sample rates it's necessary to implement the mixer and CIC filters in an FPGA.)Otherwise, that diagram is basically correct for AM. Obviously you'd replace the magnitude-calculator box with other kinds of I/Q processing if you wanted to listen to SSB, or some kind of digital modulation. All of which you could achieve in a fast ARM.

author: Yansi
author_rank: Super Contributor
timestamp: June 09, 2015, 12:05:45 am
content: I have already corrected the picture, just before I have read your comment. I recognized the error a moment later I uploaded the picture. The complex multiplication was obviously wrong.As stated in the beginning of this thread, I will have a Tayloe mixer already supplying the I and Q signals.Teasing FPGAs with this stuff would be level 999 of my work.I have already read something about the 1,0,-1,0 method (if it is what you have meant), but this does not relate to my cruel SDR experiment.Where should I put some filtering in it? Lets say I have 100ksps sampling rate at the ADC and I need only lets say 10kHz of BW for the AM reception. Where does the filter fit? Is it possible to put it after the decimation, to conserve some computing power? (filter to be computed on the lower samplerate data)

author: mark03
author_rank: Frequent Contributor
timestamp: June 09, 2015, 12:39:21 am
content: Ah. I thought you were maybe going to get rid of the Tayloe mixer do the mixing entirely in the processor (feasible for AM, and also for the VLF time signals I think someone else mentioned). That was why I referenced the "direct sampling" designs.Re: the filter, it has to go ahead of the rate change, otherwise when you throw away samples you get aliasing (spectral folding) which no amount of filtering can reverse. If you use a FIR filter you can still be clever by not computing the filter on every input sample, because you know that N-1 out of N samples will just get discarded in the decimator (for a decimation factor of N). In that case, you can sit around idle for N-1 samples, then do a bunch of work to compute the filter, then sit idle for N-1 samples, etc. Hmmmm. So why not spread the computation out somehow? This line of thinking leads directly to the polyphase filter concept. And at this point you probably need to do some reading on multirate DSPI don't know for sure about a rate change of 10. It's kind of borderline... you might be able to do it in a fast MCU with multiple stages. Much more than 10 is where special filter architectures like the CIC come into play. Of course CICs come with their own set of issues and requirements. There is lots to explore.

author: Yansi
author_rank: Super Contributor
timestamp: June 09, 2015, 12:50:59 am
content: Ok, got that with the filter computing only one time per N samples. Thats clever.But still I can't understand, where to make the selectivity of the receiver. Considering the example above, with the 100ksps I/Q sampling and no downsampling: I am receiving a 100kHz (in theory) wide block of signals. I will offset-tune the software receiver to a frequency lets say +25kHz. The AM channel I need to demodulate eats up lets say 10kHz of bandwith. How or with what I will attain that the AM demodulator will output only tha narrowed single channel, not being affected by other channels nearby in the same 100kHz block I am feeding into?If I take for example the SSB receiver, bandpass filters can be seen on the I and Q chains after decimation. Where is the filtering hidden in the AM case?

author: mark03
author_rank: Frequent Contributor
timestamp: June 09, 2015, 04:27:39 pm
content: You can put the selectivity in the block labeled "decimation LPF". Remember that that block is just to prevent spectral aliasing when you throw away samples in the downsampler block. So there is nothing preventing you from filtering narrower than you have to. In a practical implementation you'd downsample to whatever your desired output rate is (defined by codec or whatever), and just make sure that your LPF is narrow enough for the selectivity you need. (All of this assumes of course that your desired signal is centered at zero frequency after complex mixing.)The bandpass filters in the SSB case are not so much for selectivity as for phase shifting. The "Q" channel is a Hilbert transformer (filter with constant 90-deg phase shift) and the "I" channel has an equivalent filter without the phase shift, just to equalize the delay between the two paths. So the selectivity could be set either there or in the decimation filter.

author: Howardlong
author_rank: Super Contributor
timestamp: June 09, 2015, 05:07:53 pm
content: You might be interested in a complete medium wave AM receiver on a microcontroller I made a few weeks back as an experiment to show that you can take raw RF into an MCU and to all the LO, mixing, decimation, filtering and demodulation in firmware without any FPGAs, external frequency mixing or downconversion or other hardware computational assistance.It uses a Cortex M4F with a built in 80Msps ADC. It takes RF (not IF) in and it follows pretty much what's in your figure 6 above which looks like it might be from Doug Smith's DSP book published by the ARRL. (Personally speaking, I'm not over-keen on that book: it's too theoretical and assumes too much of the reader, I much prefer Richard Lyon's Understanding Digital Signal Processing book: I felt that as a beginner reading Doug's book all those years ago I didn't know much more after reading it than I did before, perhaps I was the wrong audience, I don't know).Using the Tayloe hardware mixer as you are doing is recommended as it massively reduces the computational requirement by doing a first stage of downsampling and filtering in hardware.https://youtu.be/lD3WSCN-5u0The front end bandpass filter was done in hardware, a dozen or so L's and C's for a 1MHz wide filter centred on 1MHz. There is also a cheap cascaded dual op amp providing 40dB of gain ahead of the MCU's on-chip ADC: if you had a long wire rather than a simple loop antenna you could dispense with the front end amplifier, but I broadbanded the loop antenna I used with a parallel resistor to save the effort of having to capacitively tune it.The main difference to your figure 6 above is that it samples at 2MHz and the decimators are 128:1. This level of decimation means you need a pretty serious filter. I used a 1024 tap FIR, but at 2MHz sampling rate on two channels, something's got to give on an MCU if you just use a bog standard FIR filter. For this I used polyphase filtering techniques which, in simple terms, significantly reduces your computational requirement by rearranging the FIR algorithm and coefficients a bit, and discarding the zero multiplies. The polyphase filters, mixer and NCO were written in assembler in the end to get it to work within the time frame allowed. Other optimisations included running code in zero wait state RAM, rearranging the instructions to remove any adjacent pipeline mutuality and placing them on word boundaries. The demodulation part, including the square root for the AM demod is relatively small fry in CPU terms compared to the NCO/mixer/polyphase filters so was written in C but with intrinsics to use CPU-specific optimisations. If you're only sampling at 100ksps, the post decimation filtering is much more relaxed, and there shouldn't be any need to fiddle about in assembler at all on a reasonably decent MCU.As an aside, technically speaking with a span from 500kHz and 1.5MHz, sampling at 2MHz means I was actually undersampling over 1MHz.

author: mark03
author_rank: Frequent Contributor
timestamp: June 09, 2015, 05:36:07 pm
content: Very impressive!Quote from: Howardlong on June 09, 2015, 05:07:53 pmWas this a typo? Which M4F has an 80 MSPS ADC built-in?Quote from: Howardlong on June 09, 2015, 05:07:53 pmYou should really consider a CIC implementation instead! You could save a ton of cycles. Or, use FFT block filtering, which would implement that FIR in a fraction of the cycles. Breaking the filtering/decimation into multiple stages also saves cycles. Although, maybe the goal was to dig into M4 SIMD assembly, in which case I salute you! I've been wanting to do the same myself.As an aside, it would be really nice if we could get a fast arm with a small amount of FPGA fabric included. It would make this sort of thing a lot easier. I know you can get FPGAs with hard cores (or use a soft core), but what I want is an MCU with a bit of FPGA on the side. It has to be substantially more capable than Cypress PSoC though. Something like the smallest Artix-7 (XC7A35) or perhaps 1/2 or 1/4 of that. And with no change in packaging from typical MCUs.

author: Howardlong
author_rank: Super Contributor
timestamp: June 09, 2015, 05:55:11 pm
content: Quote from: mark03 on June 09, 2015, 05:36:07 pmNXP LPC4370 is the device, 200MHz M4F plus two M0 cores with 80Msps ADC. I only used the M4F core.I was originally going to do this in fixed point, but it turned out that due to the significantly larger floating point register set, single cycle FP instructions, and the way ARM does multiple register loads, it was easier to do it all in floating point. In view of this I am sceptical you could do the same thing much faster, if at all, in fixed point. I looked at SIMD but its implementation is a bit half baked on M4.A CIC implementation might be interesting, I considered that but I don't have any real experience in doing them other than back of envelope stuff, so I stuck to what I know, and doing the polyphase decimation and properly doing ARM assembler (ie, writing it, not just reading it in a dissassembly listing) for the first time were probably enough new things for my grey matter to deal with. I learned a lot.Not sure if doing an FFT block filter is what I think you mean? Are you talking about an overlap-add/overlap-save fast convolution or something else?I found that breaking the process into more steps became self-defeating on the ARM in terms of performance, and that amalgamating processes saves expensive store and load operations. So the quadrature NCO and mixer are combined into the same code, as is the low pass anti-aliasing filter and decimation.With a polyphase implementation of a combined 1024 tap FIR plus decimation by 128 leaves you with only 8 MACs to do per sample, so 16 MACs per quadrature sample.Edit: I'm also a complete nonce when it comes to FPGAs, they have passed me by so far I'm afraid. I do have occasional dalliances into the black art, but come away more confused than I was before I started. One day....

author: Kalvin
author_rank: Super Contributor
timestamp: June 09, 2015, 06:04:58 pm
content: Referring to this schematics:http://fivedash.com/resource/LiteIISchematic.pdfThere are two continous-time op amp low pass filters. Consider those as antialising filters. Add two 8-th order switched capacitor filters after the two filters. When you generate the clock signal using the STM32 PWM, you can adjust the baseband bandwidth at your will. You don't need decimation any more. The direct-conversion receivers may suffer from DC-problem, but you can use the two other PWM-channels to create adaptive DC-signals to eliminate the DC-component in the I and Q channels. Of course the comb filters can be used instead in digital domain, but I guess you would need more than 12-bits in ADC, maybe a 24-bit delta-sigma ADC.Edit: The Zero-IF DC-offset problem could possibly be solved by AC-coupling the detector and the I/Q low pass signal paths, and then performing some spectrum shift DSP-magic Kleinstein describes below.Quote from: Kleinstein on June 08, 2015, 07:30:19 pm

author: Kleinstein
author_rank: Super Contributor
timestamp: June 09, 2015, 07:44:02 pm
content: A 12 Bit ADC will to certain degree limit the performance, getting weak stations. But at a higher sampling rate this should not be so bad, especially with some analog filtering at the Tayloe mixer. An adjustable gain might help to get most out of the 12 Bit ADCs. For good performance a higher resolution ADC would help, though I think 16 Bit with adjustable gain should be enough in most cases - unless there is a strong local station in the IF bandwidth.

author: mark03
author_rank: Frequent Contributor
timestamp: June 09, 2015, 07:53:37 pm
content: Quote from: Howardlong on June 09, 2015, 05:55:11 pmWow, I knew about the older parts in that family but hadn't realized they had such a fast ADC in the '70. I wonder what the use case is, for their big customers, I mean. I assume anyone doing serious RF would be using an external ADC.Quote from: Howardlong on June 09, 2015, 05:55:11 pmRe: FFT filters, yes, I was thinking fast convolution, but upon reflection it doesn't make sense for your polyphase decimator. It has to be applied to each of those mini-FIRs separately, and at 8 taps long, wouldn't actually be faster. (The exact trade-off point depends greatly on architecture and optimizations, but I usually see 10-30 taps quoted as parity between direct-form FIR and FFT-convolution.)I think CIC could be faster, but it depends whether you implement a clean-up FIR at the end or not. Also, it requires fixed point (the efficiency derives in part from the overflows happening the right way). Definitely less coef storage though!Cool project. On the back burner I still have plans for a digitized bat receiver (ultrasound) as an excuse to learn some ARM assembly. A lot less computation than your radio though.

author: mark03
author_rank: Frequent Contributor
timestamp: June 09, 2015, 08:01:18 pm
content: Quote from: Kleinstein on June 09, 2015, 07:44:02 pmIf using the direct-sampling approach, you gain back a lot of bits in the process of decimating to the signal bandwidth---one bit for every factor of four rate change. So, 80 MHz -> 20 kHz nets you an extra six good bits.I have a friend who's modified the OpenHPSDR Hermes shortwave receiver using an Analog Devices part with 12-bit ADC. He says most of the time he can't tell any difference between that and the 16-bit ADC in the original design. And that is a vastly more demanding application than AM radio receiver.

author: Yansi
author_rank: Super Contributor
timestamp: June 10, 2015, 02:05:23 am
content: Hi again!I have been studying FIR filters... But still doing something horribly wrong.I have made a simple template project with 32F429 using onchip ADC, DAC and DMA with corresponding circular buffers. This stuff runs pretty fine. I have a 48kHz sampling rate, buffer length selectable (now 1kByte which equals 21.333ms (1024/48kHz) of delay from ADC to DAC). Computing in 16bit precision. I am running an audio signal to the ADC and out of the DAC after.The first computational thing I have programmed in between was a volume control. That worked as expected. With 168MHz I have 3500 clocks (168MHz/48kHz) for computing each sample . This "buffer base" with the volume control (simple multiplication/division) took about 50 clocks per sample (if I remeber it right), which equals about 1.5% of CPU load. Up to this point everything is OK.I have wanted to add a FIR filter, just as a little practice - I have never done this stuff before, but I'd like to learn at least some basics... So.. I thought I'll just slap there a FIR in front of the output volume regulator. But heck.. my crappy FIR takes about 25%+ CPU time at 32 points length (with -O3) . It kinda works and is filtering stuff... sometimes overflowing somewhere. But toooo slow I think.I guess my implementation will make you laugh, but it is really my first FIR and the first implementation I could think of. It takes int16 datainas input sample and returns int16 dataoutas the filtered output, one sample at a time. The first loop advances the delay line one step, the secons loop calculates the product sum. The twodiv1anddiv2are just two scaling factors I fiddle with to get rid of teh distortions due to overflows in the filter. Cruel solution, I know.Accis int32 accumulator for the sum. Thefl(filterlength) coeficient is the length of the filter, 32 now.I took the coef. from here, because it is more probably they're right, than if I'd try to calculate them myself.https://sestevenson.wordpress.com/implementation-of-fir-filtering-in-c-part-1/I have only transformed the numbers into int16 for, +-1 is fullscale./* FIR FILTER */fl = filterlen;for (k=fl-1; k>0; k--) sample=sample[k-1]; /* shift the delay line */sample = in; /* add new sample to delay chain */acc=0;for (k=0; k<fl; k++) { /* from k=0 to M-1 */acc += (coeffs * sample)/div1; /* accumulate the product */}out = acc/div2;I understand, that the "delay line advancing loop" is not neccesary and could be solved using pointer arithmetic. I will look into that yesterday. But still I think this can by improved way more. What would you suggest to optimise and how?Thanx,YPS: I do not use ARM_DSP_Lib, I do not use FPU. Just because I want to test what can be done without it.

author: splin
author_rank: Frequent Contributor
timestamp: June 10, 2015, 11:34:11 am
content: Take a look at this, especially pages 16 onwards which explains the instruction timings and how to improve your FIR speed:http://www.arm.com/files/pdf/dspconceptsm4presentation.pdf

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2015, 01:12:16 pm
content: A few things.Firstly, the CMSIS-DSP library is there for a reason, I assume you can use that with your device, but equally I fully understand why you want to do it from first principles, it's what I'd do too.However, if you're doing things the hard way (as I did!), it's worth taking a look at the code that's generated.The typical ways to optimise M4 code are:o Unroll loops to minimise loop overheado Edit: use compiler idiomso Use intrinsic functionso Arrange data to take advantage of load and store multiple instructionso Arrange algorithms to do as much in-register processing as possible and minimise interim store and load instructionso Order instructions so they don't stall each other (eg, by avoiding use of the results of the immediately previous instruction, once you've unrolled your loops it'll be easier to accomplish too)o Run in zero wait state memory, but be aware of possible stalls due to concurrent bus access on same-segment code and data memoryo Align consecutive 32 bit instructions on 32 bit word boundariesIn your code specifically, firstly see if you can move that divide out of the loop without overflowing. You may find that reducing your coefficient resolution will help avoid overflow. Divide on M4 is slow.Avoid shifting the delay line by fiddling with your algorithm, there are a few ways of doing this, such as having two copies of your coefficients one after each other and sliding along them. If you must use a shifting delay line, either unroll the loop or use the (hopefully) optimised memmove from the c library. Regrettably M4 doesn't offer circular buffers, but then it's not a DSP!To give you some idea, I achieved an 8 point FIR in floating point M4F assembler in 34 cycles including the loads and stores by the above methods.I don't know if you are using GCC, but I wasn't too impressed with its optimisation efforts on the M4. It doesn't seem to know about the benefit of 32 bit word alignment for successive 32 bit instructions for example.There is an example floating point FIR implementation in "The Definitive Guide to ARM Cortex M3 and Cortex M4 Processors" in C that claims 3.125 cycles/MAC.

author: Kalvin
author_rank: Super Contributor
timestamp: June 10, 2015, 01:22:42 pm
content: Quote from: Howardlong on June 10, 2015, 01:12:16 pm- Scale the input and coefficients so that you don't need scaling or division inside the loops.- Arrange the divisions so that they are 2**N if possible, which can then be reduced to shifts.- Divisions can also be converted to faster multiplications when using fractional or floating point arithmetics.- Don't move the data unless it is necessary. Use circular buffers and pointers instead and keep the sample data in place.- Use circular buffers and modulo 2**N buffer sizes if possible, and see if the compiler supports modulo addressing so you don't have to test buffer boundaries.- Check the assembly code the compiler generates.

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2015, 01:25:19 pm
content: FWIW here was a recent discussion on M4F optimisationhttps://www.eevblog.com/forum/microcontrollers/how-are-micros-programmed-in-real-world-situations/msg660776/#msg660776

author: Yansi
author_rank: Super Contributor
timestamp: June 10, 2015, 02:04:37 pm
content: Thanks for suggestions guys. Some of them are familiar to me, some not. Thanks for the presentation form ARM. I will definitely read it and try to understand it. I have been loking into the code of the DSP Lib and tried to understand that. But couldn't - until now thanks to the presentation. Seems it is done exactly according to the presentation in the DSPlib.Yeah - the divide can be dismantled from the inner loop. It is way faster then and works "fine" (= scaling needed before and after the FIR). But I don't know how to calculate the scaling factors so the range could be used fully.Yeah I said that the data moving loop is unnecessary. But it was really the first implementation I have tried and that worked.I checked the assembly output with my friend yesterday - it really didn't look nice :-)Run in zero wait state memory - huh.. I can load the code in the CCM memory, possibly. Also move there all the buffers.Or I could possibly write it entirely in embedded assembly code. I have some minor experience with CM3 assembly coding, so why not try the CM4. But I think it can be done nice also in C - I will try that first.No GCC. Hate that stuff. I use Keil or occasionally IAR. (The IAR compiler is a little better than Keil I think, but I don't like the IAR GUI, that's why I stick with Keil uVision).I will try to modify my code and make some optimalisations. (or possibly try the DSPlib)How can I possibly calculate the scaling factors for the filter input and output? I have 16bit input/output data and 32bit accumulator (or do I need bigger but slower 64bit acc?). How should I scale the input and output to match the filter?Would you suggest (in general) to use flating or fixed point arithmetic on the CM4 for DSP processing (for the SDR)? I think the float can better deal with overflows - there's enough dynamic range not to overflow ever. Only the output is then scaled as neccesary. Or are there some drawbacks too?

author: ermeneuta
author_rank: Newbie
timestamp: June 10, 2015, 02:27:35 pm
content: QuoteNot necessarily... Following what Richard Lyons writes in his very good book, I have implemented in my ARM Radio project a polyphase CIC, all in floating point. The following is the comment at the beginning of the CIC block ://-------------------------------------------------------------------------// Now we decimate by 16 the input samples, using the CIC polyphase decomposition// technique, which has the advantage of eliminating the recursive// component, allowing the use of floating point, rather fast on a Cortex M4F//// A dividing by 16, order 4, CIC is used. Then a 4096-entry buffer is filled, and passed// to the baseband interrupt routine, where it is additionally filtered with a// sync-compensating FIR, which also adds further stop band rejection and a decimation by 4//-------------------------------------------------------------------------I cannot publish the source code (yet) as this project is my answer to the Keil/ARM design contest(look here :http://www2.keil.com/mdk5/contest), but after the end date of the contest, it will be published as open source.The STM32F429ZIT chip samples with two of its ADCs in interleaved mode, then a complex multiplication is done with an LO signal generated by a quadrature complex oscillator (again, thanks to Richard Lyons...), brought to zero IF, downsampled first with the CIC, then with a FIR that implements also the compensation for the droop of the response curve of the CIC (actually very small...).At this point the downsampled complex signal (at a sampling rate of 27901.786 Hz (plus or minus the tolerance of the 8 MHz quartz of the STM32F4 clock...) is bandpassed with the fast convolution method (overlap-and-discard) with a selectable bandwidth, then applied to the AM, or SSB, or CW demodulator, with a selectable AGC time constant. The output of the demodulator is sent to the on-chip DAC, using DMA with two flip-flop buffers, and the output of the DAC is sent to an external, hardware, reconstruction filter. That's all.The project is finished, all working, and I am now busy to write the documentation, the less pleasant step, but badly needed from the rules of the contest..This is a bad photo of the on-board TFT screen, also driven by the STM32f429ZIT processor, with the ARM Radio tuned to the DCF77 time/frequency standard in Mainflingen, Germany :I am intending to shot also an YouTube short video, but haven't found the time yet...Alberto

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2015, 02:57:09 pm
content: Very nice Alberto!It looks like you came to a similar conclusion as I did regarding the use of floating point rather than fixed point. In essence, the larger register set afforded to you by the FPU means you can do a lot more in-register processing than you can in fixed point, and in ARM registers are everything when trying to optimise.The Richard Lyons book is pretty much the bible of DSP as far as I am concerned. His Streamlining book is also very handy.To the OP, regarding figuring out the divide ratio, it's dependent on the number of taps, the coeffiicients and the input range. Come up with a worst case scenario and use that as the basis for your scaling.

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2015, 04:49:29 pm
content: Nice project Alberto! Thanks for pointing me to nonrecursive (and polyphase) CIC filters. The only kind I knew about were the original (Hogenauer) recursive structure. I'm guessing it's the nonrecursive structure that permits the use of floating point in this case? Guess I need to pick up Lyon's book.Can you fit a decoder for DCF77 / WWVB / etc. into the spare cycles?

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2015, 04:58:02 pm
content: Just one further comment, for some reason the CMSIS-DSP decimator isn't polyphase whereas the interpolator is. I guess no-one got around to really optimising at the algorithm level.

author: ermeneuta
author_rank: Newbie
timestamp: June 10, 2015, 05:35:04 pm
content: Quote from: mark03 on June 10, 2015, 04:49:29 pmCorrect. Eliminating the integrator part of the CIC, with its unavoidable overflow that is compensated only when you work in 2-complement arithmetic, is what permits the use of floating point. All is well described, with examples, in the excellent book of Richard Lyons, a must.A DCF77 decoder could well be coded in the GUI task, that runs at idle priority. Decoding the DCF77 is by no means a processor intensive task...Maybe, after the Friedrichshafen fair at the end of June, when I will have some spare time, I will consider that. If you perhaps have a pointer to a snippet of code that implements that decoder. that would spare me some time...Alberto

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2015, 07:22:12 pm
content: Quote from: Howardlong on June 10, 2015, 04:58:02 pmDo you know if they have different code on M4 vs M3? I have a sneaking suspicion that they do not, which I find strange considering the marketing push for the M4 core (and now to some extent the M7) is focused on this idea of a "digital signal controller". I guess there are commercial sources for optimized code, just not for hobbyists.

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2015, 07:30:32 pm
content: Quote from: ermeneuta on June 10, 2015, 05:35:04 pmSorry, I don't. I live in the US (finally updated my profile flag) so I would like to write a decoder for the new phase modulation on WWVB, which is only a few years old. (Most/all of our "atomic clock" consumer products are still using the old time code.) Wikipedia says this is similar to DCF77, so if I get around to it this summer I'll look you up!

author: Yansi
author_rank: Super Contributor
timestamp: June 10, 2015, 09:20:59 pm
content: I have just got same spare time for toying with the FIR. I have started to optimise my code. I have thrown away the "delay line advancing loop" and replaced it with pointer instead. But I have stepped onto a trouble:Here is the arm presentation, please see page 15http://www.arm.com/files/pdf/dspconceptsm4presentation.pdfThis is the slide on page 15:I dont understand the code, it seems fucked up somehow. Where is the "state" array defined and isn't there error on this line?state[stateIndex++] = in;I understand the state array as an array offiltLenlength. The FIR loop then advancesbackin tame through the array. Before each FIR computation, I need to advance 1 sampleforwardin time, that means I must increment the pointer first and then write the new sample. They are postincrementing the pointer. That leads to the first FIR product is calculated between coefficient and not the last sample added to the chain!Is there really an error?A little example: Consider a FIR of length 7. We have a state array 7 samples long, stateIndex=4. The samples are stored like this:stateIndex: V| x-4 | x-3 | x-2 | x-1 | x | x-6 | x-5 |Run through the FIR loop from k=0 to k=6. You will end up with the stateIndex in the same position. The logic tells you, that you should overwrite the oldest sample in the delay chain, the x-6 one. But if they post-increment the pointer, they are overwriting the X sample and the the first multiplication in the next FIR loop (k=0) will read x-6 (x-7 in reality) sample first, instead of the newest one! There will be an 1 sample overlap or something. Theres something wrong with their code I think.Or did I miss something?

author: mark03
author_rank: Frequent Contributor
timestamp: June 11, 2015, 12:15:32 am
content: It does seem as though the postincrement should have been a preincrement. But the presentation is really about optimization strategies, so I wouldn't get too wrapped up in it. The author probably rushed to put that slide together. It sounds like you are getting the hang of this so I would continue experimenting and learning from that.

author: Yansi
author_rank: Super Contributor
timestamp: June 11, 2015, 01:17:39 am
content: I am getting hung with anything from that presentation. If you look the second suggested method with loop unrolling - the code doesn't look right either. Multiplying one coefficient with four different samples? Wtf? Shouldnt the filtLen (loop count) be divided by four then?One doesn't have to dig much deep into the next code examples, to find there other strange things that doesn't make any sense. I suspect the document was "obfuscated on purpose" to not show exactly how to do it. I am quite confused reading it. I haven't made any progress in optimizing my code.My code now looks like this. It does 101point FIR in about 1300 clocks (12.8 per sample average). It is similar as the "standard FIR code" described in the presentation, only corrected the pointer to pre-incremented. I am stuck here. I have tried the first optimization suggested: "circular buffer alternative". But I couldn't understand it a bit. The pointer wrapping condition dissapeared in their example code. But I can't understand how it works without wrapping the pointer.sample[++sampleindex] = in;acc=0;for (k=0; k<flen; k++) {acc += coeffs * sample[sampleindex--];if (sampleindex<0) sampleindex = flen-1;}out = acc*mul2/div2;How can I optimize my FIR code according to the "circular alternative" suggested in the presentation?By the way, I have tested the ARM DSPlib, thinking it will be fast and optimized, if the function name is "arm_fir_fast_q15". But it is only a tiny fraction faster than my basic implementation above.And provides very silent output signal. So silent one must amplify an elephant to hear something, compared to my FIR which has tendency to overflow quite easily.Thanx 4 help,Y

author: splin
author_rank: Frequent Contributor
timestamp: June 11, 2015, 03:50:07 pm
content: Quote from: Yansi on June 10, 2015, 09:20:59 pmYes. The post-increment means that the filtering processes the samples in the order:x-6, x, x-1, x-2, x-3, x-4, x-5and leaves sampleindex pointing at x-6. The next sample, x+1, overwrites x-6, and the next filter takes the samples in order:x-5, x+1, x, x-1, x-2, x-3, x-4The post-increment probably is a mistake but that code will work fine so long as the coefficients are in the matching order 6, 0, 1, 2, 3, 4, 5But as mark03 says, don't get hung up too much on the detail - the presentation is about techniques to get the best out of the M4, not production ready code. Its just a guide.

author: splin
author_rank: Frequent Contributor
timestamp: June 11, 2015, 06:01:06 pm
content: Quote from: Yansi on June 11, 2015, 01:17:39 amThat is an error. It should probably post increment k when fetching the coefficients (as shown in the code on page 29), or use 4 different sum variables (as shown on pages 32 & 33).QuoteYes, but it's just not been included in that code snippet. If you look at the example code on page 29 for example it has this just before the loop:filtLen = filtLen << 2;QuoteI doubt that; I think it's just that it's pitched at people who are familiar with DSP and these types of coding techniques, but not specifically with the Cortex M4 DSP instructions/architecture.QuoteI don't think the 'circular buffer alternative' on pages 19 to 22 is very clear - you probably had to be at the presentation, but these are just notes. However the idea is to make the buffer of input samples longer than the filter length so that you can be sure that stateindex won't wrap-around in the filter loop so that you can eliminate the 'if (stateindex < 0)' test in the inner loop, saving 4 cycles. There is an extra cost of copying samples though.In your case with a long filter, it would be simpler to eliminate the wrap-around test using:sample[++sampleindex] = in;acc=0;k = 0;while(sampleindex >= 0) {acc += coeffs[k++] * sample[sampleindex--];}while(k < flen) {acc += coeffs[k++] * sample[sampleindex--];}out = acc*mul2/div2;You can significantly improve on the above 8 cycles/tap by implementing loop unrolling. Your data is 16 bit, so if you're coefficients can also be be limited to 16 bits or less then using the SIMD instructions will double the speed again with 2 x 16x16 multiply accumulates in a single instruction as shown on page 27. Applying all the techniques shown you should be able to achieve the stated 1.625 cycles/tap, but this assumes that there are no extra delays due to instruction fetch wait states or memory bus delays due to instruction/data contention.Quotearm_fir_fast_q15 uses SIMD and loop unrolling so should be much faster than yours so I'm not sure why your's is so slow. Note that the filter length must be even so you can't have a 101 tap filter. Also note the scaling limitations:This fast version uses a 32-bit accumulator with 2.30 format. The accumulator maintains full precision of the intermediate multiplication results but provides only a single guard bit. Thus, if the accumulator result overflows it wraps around and distorts the result. In order to avoid overflows completely the input signal must be scaled down by log2(numTaps) bits. The 2.30 accumulator is then truncated to 2.15 format and saturated to yield the 1.15 result.With a filter length of 100 or 102 taps you need to scale the input down by 6 or 7 bits to prevent overflow. However, as you say the volume is very low I suggest you need to check the input sample and coefficient scaling.Have fun!

author: rockets4kids
author_rank: Newbie
timestamp: June 11, 2015, 06:57:57 pm
content: I've only just skimmed this thread, but two things:1. For a Tayloe modulator you want a square wave source, so the Si570 (or similar) is generally preferred.2. There is already a project that does just about *exactly* what you want: mcHFhttp://www.m0nka.co.uk/

author: Yansi
author_rank: Super Contributor
timestamp: June 11, 2015, 08:00:55 pm
content: splin: Thank you for your detailed reply. I have toyed with my FIR implementation some long hours again, then looked into the ARM presentation and I might possibly got it! Hurray! Just to revise some statements:Quote from: splin on June 11, 2015, 06:01:06 pmThe "final optimised FIR code" is indeed faulty. I have finaly simulated the code in great detail DaveCAD style, when I was heading home by train today. It really took my nerve, but I solved the problem. There are variables interchanged!Now we can piece the presentation together:And I can prove it with my DaveCAD simulation!On top you have the state buffer with d(n) samples. The braces over the pairs are the 32bit data pairs for the dual-multiply-accumulate SIMD instructions. Under the buffer there are the sums with their related SIMDs. I have simulated four steps (2 inner loop runs). The small rectangles represents the four SMLAD instructions performed with their respective data inputs:Each inner loop run consists of 2 groups of 4 SIDMs: The firs group is calculated as x0c0, x1c0, x2c0, x3c0. The second group then x2c1, x3c1,x0'c1,x1'c1. (Consider the apostrophe marked variables as newly fetched pairs of samples, c1 as new pair of coefficients). This and only this way it will work.Also note that the coefficient array must be in reverse order, the FIR is calculated backwards, the last multiplied samples are the newest ones shifted in the state buffer from the "right side".I haven't made my implementation of this yet, beacause I have just arrived and even haven't had dinner :-)After dinner I will put a few words about why the DSPLib was so slow and produced so weak output - I probably figured that out too.. maybe.

author: Yansi
author_rank: Super Contributor
timestamp: June 11, 2015, 08:35:59 pm
content: Oh, I forgot the conclusion: There's nothing wrong with the suggested optimalizations. But all of them are done wrong in the presentation :-)DSPLib being slow: The DSP lib code for calculating blocksizes <4 is non-optimal, is slow. Almost the same as mine. Thus the same speed. You must calculate a block of 4 or more, better a multiple of 4 samples, to never run the slow code..And I see there one other odd thing, but I might be overloking something (the code there is quite messy): Where the hell is the loop, that scrols the state buffer after each FIR function call? You need to shift the state buffer blocklength samples left after each processing. (so the pointer never wraps circularly, always starts from the zero index). Where did that loop go?Conclusion2: The suggested optimizations need a second loop for shifting the statebuffer left by blocklength samples before each call of the FIR calculation. (If I got right how the unwinded linear buffer works). I don't see there any loop to do this, which is quite strange. The DSPlib FIR probably haven't worked at all, thats why I wass getting only ultraweak output. There has been no scaling on the input!Conclusion3: The more data you process at once, the more effective this implementation gets. Because there is (should be!) one statebuffer shift per call and the implementation is optimal only for multiples of 4 samples. So how big blocks do you calculate at once in your SDR radios?I will try to implement the code myself now. I don't trust the DSPlib now. It was made too much universal that it lacks the effectivity I am looking for.

author: danfo098
author_rank: Contributor
timestamp: June 11, 2015, 09:13:53 pm
content: Here are some more FIR filter code that you can try, it uses a 256 byte "autoroll" circular buffer so for it to work the number of coefficients must be equal or less than that. Haven't actually tested it on the M4 yet so don't know how fast (or slow) it will be.Code:#include <stdio.h>#define NO_COEFFS 7#define TEST_LENGTH 1024float coeffs = {0.1f, 0.2f, 0.3f, 0.4f, 0.3f, 0.2f, 0.1f};void fir_init(float gain){uint8_t n;for (n=0;n<NO_COEFFS;n++){coeffs *= gain;}}void fir(float in, float *out){uint8_t n;float acc;static uint8_t sampleidx = 0;static uint8_t sampleinc = NO_COEFFS + 1;static float samplebuf = {0.0f};samplebuf = in;acc = 0.0f;for(n=0;n<NO_COEFFS;n++){acc += coeffs * samplebuf[sampleidx--];}sampleidx += sampleinc;*out = acc;}void fir_fast(float in, float *out){uint8_t n;float acc;static uint8_t sampleidx = 0;static uint8_t sampleinc = NO_COEFFS + 1;static float samplebuf = {0.0f};samplebuf = in;acc = 0.0f;acc += coeffs * samplebuf[sampleidx--];acc += coeffs * samplebuf[sampleidx--];acc += coeffs * samplebuf[sampleidx--];acc += coeffs * samplebuf[sampleidx--];acc += coeffs * samplebuf[sampleidx--];acc += coeffs * samplebuf[sampleidx--];acc += coeffs * samplebuf[sampleidx--];sampleidx += sampleinc;*out = acc;}int main(void){uint16_t n;float inbuf = {0.0f};float outbuf = {0.0f};inbuf = 1.0f; /* test the impulse response */fir_init(1.0f); /* set filter gain */for(n=0;n<TEST_LENGTH;n++){fir(inbuf, &outbuf);}for(n=0;n<15;n++){printf("Out sample no %d: %f \r\n", n, outbuf);}return 0;}

author: Yansi
author_rank: Super Contributor
timestamp: June 11, 2015, 09:24:55 pm
content: Thanks for the code. Looks the same as mine (see page 2 of this thread please). It wasn't fast. The optimized version I am implementing now should be better (If I can make it work).Can you please explain me the autoroll buffer?rockets4kids: I am sorry, I've skipped your answer! Si570 is nice, but look at its price. I can have three DDS chips for its price.At the page you have posted (http://www.m0nka.co.uk/) I got a big laugh when I saw this:Quote

author: rockets4kids
author_rank: Newbie
timestamp: June 12, 2015, 04:49:43 am
content: Which prices are you comparing? You can get the SI570 at Digikey for about $13 @q1. Legitimate AD9850/1s are about the same price, maybe more.I'm guessing you are looking at the cheap eBay modules? Do you know anything more about those, particularly the signal output above 100 MHz?

author: Yansi
author_rank: Super Contributor
timestamp: June 12, 2015, 08:58:18 am
content: I compared Si570 from Mouser (16USD) and AD9834 (about 4-5USD) on china market (ebay/aliexpress). I have no experience with the AD9850/1 modules on ebay, but I've heard that the output lowpass filter is not good.

author: Kalvin
author_rank: Super Contributor
timestamp: June 12, 2015, 09:34:34 am
content: Quote from: Yansi on June 12, 2015, 08:58:18 amJust forget the analog output, bypass the filtering and use the digital output.

author: danfo098
author_rank: Contributor
timestamp: June 12, 2015, 04:47:19 pm
content: Quote from: Yansi on June 11, 2015, 09:24:55 pmThe buffer is 256 bytes long and the variable used to index it is an unsigned byte (0-255). Adding 1 to 255 will roll over and become 0 and so you never need to check if the index is out of bounds.

author: rockets4kids
author_rank: Newbie
timestamp: June 12, 2015, 09:12:47 pm
content: AD9834 appears to be limited to 75 MHz, which means your top frequency with a Tayloe mixer is going to be 18 MHz.Do you know if those parts from eBay/Aliexpress are genuine or knockoffs? If knockoffs, do you know how well they compare to genuine parts? Jitter is the specific parameter you are really interested in here.If you are only looking to do 40 meters you will probably be just fine. At higher frequencies you may run into issues, particularly if you want to decode digital protocols. I'm not sure what your goals are here, so none of this may matter anyway.

author: Yansi
author_rank: Super Contributor
timestamp: June 12, 2015, 10:06:01 pm
content: danfo098: That should work, but is limited to a length of 256. I don't know how long FIR filters would I need for the SDR (noone has answered my question about buffer lengths yet) but this should save some machine time. Problem is how the compiled code for the 8bit variable will look, it might be slower though.rocket4kids: I don't know what these are, we will see :-) The DDS is up to 75MHz, which means maximum output of about 30MHz. For the Taylou mixer you need 4-times frequency, so up to 7MHz (40m) band. But that's detail, now I think I should focus on the software part, because I am a novice in the wonderful world of digital processing. I am more familiar with HW design (power stuff), but not so much with RF... so I'd like to learn something new from both areas.The plan is to receive the local AM transmitter on about 650kHz. Then I can apply some filtering to it and possibly decoders for other modes and shift the work to other SW frequencies up to 7MHz.I have talked with a friend from local university, he warned me that the Tayloe CMOS mixers do have really bad corner (1/f) noise. I will try to first just demodulate directly the IQ data though (simplicity rulezz), then possibly add the complex mixing.The only thing missing now is the hardware. I am going to make some really simple HW kit, as I have already said, with the AD9834 DDS, Tayloe with PI3B3253 and a wideband input amp using some JFET or BJT... The input filtering is going to be on a dedicated board... Don't consider it any final application, this will be only for testing purposes.Now I have been experimenting with FIR filtering. Unfortunately I have had no free time to test my FIR implementation using SIMDs yet. I will possibly test it now (if I won't get too sleepy) or maybe tomorrow....

author: Howardlong
author_rank: Super Contributor
timestamp: June 12, 2015, 10:43:03 pm
content: Yansi: you already have the basis of a receiver, I would continue as you've been doing, get some hardware made up, and see how you get on. Looking at ot from where I'm sitting you're in danger of doing what I am frequently guilty of: analysis paralysis!I built my first Tayloe mixer about 12 years ago, we were looking at using SDR techniques for satellite transponders. I hand wired it on breadboard. It worked, I used a 42.8MHz canned oscillator* for 10.7MHz IF that we were commonly using at at time in our payloads. No, it might not've had the best phase noise, but I would worry about that later if all you're doing is learning about SDR and you're not expecting the performance of a $10k receiver.Personally speaking, although phase noise is important, I would not be too concerned about it at this stage, because, like me, you'll probably learn about it by seeing it and what the practical affect is particularly with strong adjacent channels.* The first oscillator I used was a quick programmed canned unit. These tend to use PLLs based on an internal reference. This demonstrated very well phase noise and its effects, but as a technology demonstrator it worked well enough. I subsequently moved to a "proper" (non-derived) custom oscillator. FWIW, as a result of this work, these oscillators were subsequently flown on a successful SDR based payload that was launched during an ISS EVA about five years ago.

author: Howardlong
author_rank: Super Contributor
timestamp: June 12, 2015, 11:21:37 pm
content: For medium wave/AM you could use an Si5351 which you can program up to directly generate biphase quadrature LO at these frequencies suitable for your switches. I have used them extensively in SDRs since 2012, but it has to be said purely for clock distribution and generating self-test signals in the RF path rather than for LO generation, however recently I have seen a growing band of proponents using them in Tayloe mixers.They are a bit fiddly to program, but there is a register value generator program. Also make sure you get the B revisions, I had a 7% failure rate in the earlier A revision in production, where they showed unstable clocks. You can tell the revision, it's thesecondletter after the 5351. So, Si5351A-B is revision B but Si5351B-A is the earlier revision A.

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2015, 12:39:53 am
content: Thank you Howardlong for sharing experience with these. Failure rate of 7% is pretty bad I think for a production device.Someone has already suggested Si5351 (and the Si570 I have seen in some SDR constructions). But I didn't choose those, because of two things: Price, programing complexity (especially the 5351). I am going to use AD9834. It has got a builtin comparator, to produce clock out of the analog signal. It also provides output of the MSB/sign bit of tha DAC binary word - but I think the MSB bit output cannot be used (or can be? I can't think much now, at 2 AM :-) ), so the analog comp with some small filter in front should be used to produce the digital clock from the DDS.I haven't quite understood what you have meant with the "analysis paralysis".. .but sure, I can hack the frontend together using standard off-the-shelf cocmponents I have here, like 4052, 7474 and some suitable crystal osc... for the local AM transmitter with 750kW output power it would work too almnost for sure :-)

author: Howardlong
author_rank: Super Contributor
timestamp: June 13, 2015, 01:19:10 am
content: Prior to the production run I hand built ten units to characterise them and come up with a testing procedure. All good. We hit a production run of the first 1ku and we find this feature, Silabs said it should work, next thing I know they bring out a B release and we no longer have failures. Luckily it was a 10 pin MSSOP so a 2 minute soldering job.Not sure about one off pricing but at 1ku they're under $1.The point I was trying to make about analysis paralysis was that as far as I can see you already have more than enough expertise yourself to get something going already as far as I can see. Sure, there may well be some tweaks you can do, but I'd say you're pretty much there.FWIW I spent about four days solid optimising my ARM FIR and NCO/Mixer, sure it was a baptism of fire, never having actually _written_ ARM assembler,(there is a difference between looking at compiler generated code and writing it!) but I learned a lot doing it, not just about the algorithms and ARM assembler, but also about compiler limitations and getting the best performance out of compilers and ARM devices in general.

author: LukeW
author_rank: Frequent Contributor
timestamp: June 13, 2015, 06:56:23 am
content: Maybe this will also be of interest.http://openradio.net.au/index.php/Main_Page

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2015, 03:46:28 pm
content: Howardlong: I don't where I have been looking for the price last time, but now I see the 5351 for about $1.2 at Mouser @ 1pcs. That really is worth looking. Maybe in my later design. Programming of this device is reminding me the PAL video codec I once wrote software for, or digital cameras we use at work - all with over hundred registers to be set.I will order some of those 5351 too, will be useful.LukeW: This is the same stuff over and again. Same mixer circuit, same input transformer and passive input only. But I don't quite like that. The gain should not be concentrated in the Tayloe mixer, because as I mentioned th mixer itself has big 1/f noise, and the OPamps after the mixer the better they are still a lot of input noise voltage (current noise is not an issue on these low impedances). The opamp should not have much gain, only few tens is the optimum I think. Discrete stages before the mixer should be used, they do have lower noise figure.Some progress is being made: I have implemented the FIR using SIMDs. The code is below. It is not tested yet if it really calculates right, I have only measured the computational time yet. Sadly - it still does not meet the numbers ARM refered to in their DSP presentation. But the code is I think mostly the same..? So why the bigg difference? The claim 26 cycles per loop run. I measure about 839 ticks per 26 loop runs (104 tap filter), which equals about 32 clocks per run. Something must be still wrong. (but close enough! Only 2cycles per MAC now!). The compiler (Keil uV5) was set to O3. (I have just tested with "optimise for time" option and it gives about 29 cycles per run. 1.8 cycles per MAC).Something should be also done with the buffer shifting loop before the FIR loop. I will probably try the "naturally overflowing" 256 samples long buffer. But little hope here, the compiler output is unpredictable.Here's the code:Code:/* FAST SIGNED INT16 FIR FILTER- calculates 4 samples each call- statebuf should be long filterlen+3- number of coefficients (filterlen) should be multiple of 4- coefficient array should be time reversed.- 32bit accumulators*/void FIR16(int16_t *coeffs, int16_t *statebuf, int16_t *in, int16_t *out, uint16_t filterlen){uint32_t i;uint32_t fl;int16_t *inptr, *outptr;int32_t sum0,sum1,sum2,sum3;int32_t x0,x1,x2,x3;int16_t *stateptr;int32_t *coefptr;int32_t c;/* shift the state buffer 4 samples left */fl = filterlen-4;for (i=0; i<fl; i++) statebuf = statebuf[i+4];/* add four new samples */inptr = in;statebuf[filterlen+2] = *inptr++;statebuf[filterlen+1] = *inptr++;statebuf[filterlen+0] = *inptr++;statebuf[filterlen-1] = *inptr++;/* prepare the process loop */stateptr = statebuf;coefptr = (int32_t*)coeffs;sum0=sum1=sum2=sum3=0;x0 = *(int32_t*)(stateptr++);x1 = *(int32_t*)(stateptr++);fl = filterlen>>2;outptr = out;CK1 = SysTick->VAL;/* run the filter loop */for (i=0; i<fl; i++) {c = *(coefptr++);x2 = *(int32_t*)(stateptr++);x3 = *(int32_t*)(stateptr++);sum0 = __SMLAD(x0, c, sum0);sum1 = __SMLAD(x1, c, sum1);sum2 = __SMLAD(x2, c, sum2);sum3 = __SMLAD(x3, c, sum3);c = *(coefptr++);x0 = *(int32_t*)(stateptr++);x1 = *(int32_t*)(stateptr++);sum0 = __SMLAD(x2, c, sum0);sum1 = __SMLAD(x3, c, sum1);sum2 = __SMLAD(x0, c, sum2);sum3 = __SMLAD(x1, c, sum3);}CK2 = CK1 - SysTick->VAL;*outptr++ = (int16_t)(sum0>>15);*outptr++ = (int16_t)(sum1>>15);*outptr++ = (int16_t)(sum2>>15);*outptr++ = (int16_t)(sum3>>15);}Is there something still wrong, or is it just the compilers evil mind? (--> should I try to rewrite it in assembly? I am not much against that idea... But I should study how the function parameters are beeing given to the function.

author: Howardlong
author_rank: Super Contributor
timestamp: June 13, 2015, 04:16:37 pm
content: You may well be doing this already, but typically when I'm hand optimising I turn off compiler optimisation other than the use of register variables, it gets mighty confusing otherwise.

author: Kalvin
author_rank: Super Contributor
timestamp: June 13, 2015, 04:26:27 pm
content: Check your datatypes. For example, your samples and coefficients are int16_t but you are accessing them as int32_t. Not only this may burn cycles, but also you are processing invalid samples.Edit: Actually there is nothing wrong as you are using the intrinsic SIMD functions like __SMLAD which assumes that one provides two int16_t samples at once packed as one int32_t.

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2015, 04:46:34 pm
content: Hmmm.. It really computes shit. I jsut gave 8 random coefficients (0,1,2,3,3,2,1,0) and random input (0,1,2,3). The FIR returns (0,3,8,14) but should return (0,0,1,4) I think.The coeffs and data ara accessed as 32bit for the SIMDs. The coeff pointer should be incremented by 32bits (2 coeffs at once), the sample pointer should be incremented by 16bit (1 sample), but still reads 32bit data (2 samples) for the SIMDs.I am debugging now... and searching for the fucking error.

author: Kalvin
author_rank: Super Contributor
timestamp: June 13, 2015, 04:53:22 pm
content: About the optimization I found this:"For best performance you typically use the highest optimization level, -O3.However, we have found that when code is carefully written to group loadand store operations together (per section 20.4.6.1), using -O3 mayreorder instructions leading to worse performance. You may have to experimentwith the optimization level to determine the best performance for a particularalgorithm."See if the default optimization level -O2 gives better results.

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2015, 05:07:24 pm
content: I don't like compiler-dependent code performance. I'd rather rewrite it in assembly... after I find the F-word error.Seems it is loading data which it should, but then something is screwed and the output does not match the hand-calculated convolution.And no, I haven't forgot to time-reverse the coefficients... That must be something else...So I have simplified. Convoluting (0,1,2,3)x(3,5,7,9) should produce (0,3,11,26,...). First error has been found: samples must be filled reversed, so this code must go in reverse order. The state buffer must look like (0,0,0,0,1,2,3).Code:/* Must be reversed!!! */statebuf[filterlen+2] = *inptr++;statebuf[filterlen+1] = *inptr++;statebuf[filterlen+0] = *inptr++;statebuf[filterlen-1] = *inptr++;... but still returning (0,5,13,28,...)... note the nonzero numbers being incremented by 2... mmm... interesting.Sheldon and his brain! Sheldon and his brain! .... (if you know the TV series...)I have found the root cause of the problem.Why the evilest hell, does the ARM load the 32bit coeff data with SWAPPED LOW AND HIGH HALFWORDS?!The x0, x1, x2, x3 data are loaded as standard BIG ENDIAN. But for some uknown reason for me, the c (coeff) is loaded with swapped low/hig halfwords. Why?

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2015, 06:16:07 pm
content: Hmm.. further analysis showed, that idiotic me can't define a const array with a sequence of odd numbers in reverse order.Look:Code:const int16_t coeffs = {9,7,3,5};Ther's your problem!(If you know the Mythbusters...)Fuuuu. Now it should work!Final performance measurements: 104 taps filter, block of 4 samples, tick count only for the FIR loop itself:834ck per O3753ck per O3+Os839ck per O2832ck per O2+OsThe whole function call with the statebuffer shifting loop: 1310ck per O3 and after optimizing the shifting loop for 32bit accesses the final score is 860 clocks (O3+Os). C-level only optimizations. That equals almost exactly 2 clocks per filter tap! Pretty impressive! And I think it can be pushed a few percent further ussing assembly code.Here is the final code for those interested:Code:#include "fast_fir16.h"/* FAST SIGNED INT16 FIR FILTER- calculates 4 samples each call- statebuf should be long filterlen+3- number of coefficients (filterlen) should be multiple of 4- coefficient array should be time reversed.*/__IO uint32_t CK1, CK2;void FIR16(int16_t *coeffs, int16_t *statebuf, int16_t *in, int16_t *out, uint16_t filterlen){uint32_t i;uint32_t fll;int16_t *inptr, *outptr;int32_t sum0,sum1,sum2,sum3;int32_t x0,x1,x2,x3;int16_t *stateptr;int32_t *stateptr32;int32_t *coefptr;int32_t c;/* shift the state buffer 4 samples left */stateptr32 = (int32_t*)statebuf;fll = filterlen>>1;for (i=0; i<fll; i++) {*stateptr32 = *(stateptr32+2);stateptr32++;}/* add four new samples */inptr = in;statebuf[filterlen-1] = *inptr++;statebuf[filterlen+0] = *inptr++;statebuf[filterlen+1] = *inptr++;statebuf[filterlen+2] = *inptr++;/* prepare the process loop */stateptr = statebuf;coefptr = (int32_t*)coeffs;sum0=sum1=sum2=sum3=0;x0 = *(int32_t*)(stateptr++);x1 = *(int32_t*)(stateptr++);fll = filterlen>>2;outptr = out;/* run the filter loop */for (i=0; i<fll; i++) {c = *(coefptr++);x2 = *(int32_t*)(stateptr++);x3 = *(int32_t*)(stateptr++);sum0 = __SMLAD(x0, c, sum0);sum1 = __SMLAD(x1, c, sum1);sum2 = __SMLAD(x2, c, sum2);sum3 = __SMLAD(x3, c, sum3);c = *(coefptr++);x0 = *(int32_t*)(stateptr++);x1 = *(int32_t*)(stateptr++);sum0 = __SMLAD(x2, c, sum0);sum1 = __SMLAD(x3, c, sum1);sum2 = __SMLAD(x0, c, sum2);sum3 = __SMLAD(x1, c, sum3);}*outptr++ = (int16_t)(sum0);*outptr++ = (int16_t)(sum1);*outptr++ = (int16_t)(sum2);*outptr++ = (int16_t)(sum3);}/* END OF FILE */I am now trying to run audio through... guess what! It does not work. Output buffer always zeros. Another fail! But where...

author: BFX
author_rank: Frequent Contributor
timestamp: June 13, 2015, 09:01:24 pm
content: You know as usual problem is between chair and keyboardBut nice results

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2015, 09:13:43 pm
content: Hi MarošAs you've said, exactly. There were two errors in the sample shifting loop. I have already corrected the code above. There was index missing and the -2 subtraction was also wrong.stateptr32 = (int32_t*)statebuf;fll = filterlen>>1;for(i=0; i<fll; i++) {*stateptr32 = *(stateptr32+2);stateptr32++;}Now it works quite well. Fast and also computes the right numbers. I have connected subwoofer through my "little DSP gizmo" :-)Here's how it looks like. As simple as it can be.

author: Howardlong
author_rank: Super Contributor
timestamp: June 13, 2015, 09:48:36 pm
content: If I had a $ for every time etc!

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 04:10:58 pm
content: HiHave I understood it right, that decimating filter (by integer of 4 for example) means computing the FIRs like this? Is this the "box-car" filtering technique literature is often reffering to?

author: Kalvin
author_rank: Super Contributor
timestamp: June 14, 2015, 05:06:27 pm
content: Yes. Basically you combine a decimation FIR filter with the decimation operation (see 2.3 Implementation):http://dspguru.com/dsp/faqs/multirate/decimationUsing a simple multirate technique, you can make things in very efficient way, too:http://www.ws.binghamton.edu/fowler/fowler%20personal%20page/EE521_files/IV-05%20Polyphase%20FIlters_2007.pdf

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 05:20:06 pm
content: The same calculations are done, but four at a time so that the state shift only needs to be done 1/4 of the time in your example.Doing it this way in ARM allows....O Use of load and store multiple instructions (cheaper than several separate distributed loads and stores)O More concentrated, but cheaper, register-register operationsO Fewer pipeline stalls by rearranging and interleaving mutually exclusive calculationsO Loop unrolling to reduce loop overhead (reduce cost of jump as well as end-of-loop calculation)ARM has 16 32 bit registers and, once you ignore the stack and and frame pointers plus the PC from these, attempting to use as many of the remaining 13 registers as possible is the general way to improve speed. Loads and stores are expensive, and as ARM can't do any operations other than load and store on memory, you need to load up the registers before you can do any computations.By using either directly adjacent loads and/or the load multiple instructions, you can save time due to the way the pipelining works with those instructions, so in general they are done all together to load up as many registers as possible. Then the in register computations are done, then the result(s) stored, again using directly adjacent stores and/or store multiple.So unlike x86, the architecture really pushes you to use lots of registers simultaneously if you want ultimate performance. This inevitably leads to somewhat head scratching code. Typically, I write what I'm doing in a code section and get it working functionally, then #ifdef around that section, leaving the original source code there, but rewrite it under a #else for computational efficiency. It is not uncommon for me to have at least one comment per line in these circumstances because it won't be immediately obvious what planet I'm coming from to do it that way. This is more for me when I come to look at the code a week or a year later.Because the M4F has and additional 32 registers, somewhat counter intuitively you can make just as efficient code, if not more so, using floating point as you are afforded a much larger register set, pandering to,the ARM's strength in in-register computation.

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 05:32:15 pm
content: Quote from: Kalvin on June 14, 2015, 05:06:27 pmI am not sure that doing a polyphase decimator is going to be worthwhile for a decimation by four, but for larger decimations it most certainly will be computationally worthwhile. From a complexity perspective I would try to avoid it, but sometimes it's essential.If you want an example of a polyphase resampler, look up updirfn. This does interpolation as well as decimation. Once you've got rid of the Python nonsense, there's a header file with the guts in it.There are surprisingly few real source code examples of polyphase decimators. There are plenty of diagrammatic representations though which tend to make my head hurt!

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 06:28:25 pm
content: Now I am thinking how I should implement the decimating FIR into the ARM, using again some sweet optimalization techniques. But it seems I could reuse the code I have now, only modify it to use multiple pointers, initialized with offset of M samples, where M is the decimating factor.I have just looked into the arm_fir_decimate_fast_q15.c on their implementation. Seems they calculate only two samples at once, instead of four (as I have in my implementation now). Is there any reason why only two at once instead of four? (I suspect there is not enough registers left to do the calculation of four at once efficiently).Now I use 48kHz input sampling rate. Because the audio I am interested in (telephony) has the range of only about 300Hz to 3kHz, would it make sense I should apply decimation by 4, to produce output of 12kHz (or possibly 6x, downto 8kHz), to save computing time?If I understand that right, the decimating FIR filter is still calculated as for the higher/input sampling rate, 48kHz in my example? That would lead to very high order of the filters, to get the desired bandwidth/selectivity in the receiver. Does it make sense to design the decimating FIR only to suppress aliasing and then use separate sharper filtering on the downsampled signal?Look what I have found!MC1350 (Datasheet)- Seems like a reasonable part for my final design :-)

author: Kalvin
author_rank: Super Contributor
timestamp: June 14, 2015, 06:42:53 pm
content: Quote from: Howardlong on June 14, 2015, 05:32:15 pmPolyphase is nice if one wants to keep a constant load on the CPU ie. for each new sample something will be processed. This will require a simple state machine in the filtering routine and downstream processing routines. Yes, it may cause some headache, too. The good property of the polyphase implementation is that it will keep the CPU load typically quite constant as the CPU will compute partial results at every sample instant.The other solution is to process the complete decimator every fourth sample. Implementation will be straightforward, but the CPU will be very busy at every fourth samples. Depending on the implementation this may be a problem or not if the CPU cannot do real-time processing task at every sample instant.Quite often in real-time applications (like audio signal processing) one needs to do some real-time processing at each sample instant and output updated data at sample rate. If the data cannot be processed at each sample instant due to long processing delay, this may be a problem. The cure is to add more raw CPU horsepower or do something clever, like polyphasing.

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 06:55:29 pm
content: I use input and output buffers of 1K length now (about 20ms at 48ksps), so calculations are done in bursts whenever the CPU has time && buffers are not full. That way I can even pause the CPU for a few milis to do other tasks (considering it can refill the buffers quick enough in the remaining time).I am also going to use FreeRTOS probably to make the programing of the UI simplier.I like the asynchronous processing much more. Here is no need to avoid the input-to-output delaying of the signal.

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 07:02:33 pm
content: Quote from: Yansi on June 14, 2015, 06:28:25 pmThey probably ran out of registers. If you look at the floating point version, ISTR it's four at a time.The CMSIS DSP decimator at present is NOT polyphase but functionally it will do the job.With higher decimation, higher tap FIR filters are going to be needed, or some other means of anti alias filtering. That is where polyphase filtering and decimation comes in.However, unless you really are running out of CPU, I would keep it modular and simple. Having to amalgamate functionality can be great for performance but is a bitch for maintenance. That's just one of those engineering conundrums, compromise!Edit:Yes, decimate by 4 or 5 or so, then do your more stringent processing on that. I did almost exactly that in the narrowband telemetry decoder for the FUNcube series of satellites.

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 07:35:24 pm
content: Ok, now I can filter data using FIR (or do the Hilbert which is also FIR). For my original idea, I would like to test AM demodulation first, because it seems to be the simpliest and most straightforward.I obviously do need a square root. :-) Until now, for an integer sq root I've been using some fast implementation found on the web. It calculates really integer square rooot, not fractional. But I think it doesn't really matter here. The implementation finds the root in about 280 cycles on Cortex M0 and I think that was with O0, not O3 even Os.Haven't tested the performance on CM4 or CM3 yet.It could be worth a consideration to use teh FPU here. Convert the u32 to f32, find the root with the FPU (does in 14 cycles I think) and then convert it back to u16.But there is a catch. The square root returns only positive values. So how can I get rid of the DC offset in the signal the easiest way? I haven't googled yet, so I am going to do so now.There is the code for the fast u32 sqrt. It also returns the remainder.Code:/*** @brief Calculates square root of aa, integer numbers. Returns also* the remainder. So for 27 it returns 5 and remainder of 2.* @note None* @param aa: integer number to be rooted, input 2^32-1 (4294967295) maximum* @param *rem: pointer to the remainder variable to be filled* @retval integer trunc of square root of aa*/uint16_t sqrt32r(uint32_t aa, uint32_t *rem){uint32_t b = 1 << (32-2);uint32_t a = 0;while (b != 0) {if (aa >= a + b) {aa -= a + b;a += b << 1;}a >>= 1;b >>= 2;}if (rem) *rem = aa;return a;}

author: Kalvin
author_rank: Super Contributor
timestamp: June 14, 2015, 07:38:28 pm
content: Quote from: Yansi on June 14, 2015, 06:28:25 pmYou can think the decimation as follows:You have a sample rate of 48kHz but your signal is only in range 300Hz - 3kHz. You could process the signals 300Hz-3kHz at 48kHz sample rate, but you are wasting cycles as the required sample rate is 6kHz (twice the highest signal component).So, you want to decrease the sample rate. From the sampling theory you know that 6kHz sample rate is the absolute minimum for the 3kHz signal bandwidth. But in order to make your life a bit easier, the 12kHz sample rate is a good compromise as the decimation filter could be a bit relaxed etc. and you won't get aliasing that easily. As a result, you want to perform 1:4 decimation.Now, you need to filter all the frequency components above 3kHz ie. you want to create a 3kHz low-pass filter at a sample rate of 48kHz. You want to have a FIR filter as it is suitable for decimation process, it has a linear phase response, it is always stable etc.Here is the best part: Yes, you need to compute the 3kHz low-pass FIR at each sample instant ie. at 48kHz rate. However, as part of the decimation process you will use only every fourth output sample of the decimation filter. As the FIR filter doesn't have any recursive structures as an IIR filter has, you need to just compute the FIR at every fourth sample instant that you are interested in. You don't need to evaluate the FIR filter at those sample instants that you will discard anyway as a result of decimation.Polyphase? Well, polyphase would distribute the processing load more evenly.About software architecture. Divide the software into two parts: "foreground" and "background".First part is the "foreground" process ie. the real-time signal processing part which will be handled in the interrupt service routine at sample rate of 48kHz.The second part, "background" will be at main() function level handling the UI and other non-real-time stuff. The "background" it will be interrupted by the "foreground" process at 48kHz rate, thus the "background" process will get the remaining processing cycles which are not used by the "foreground" process.

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 07:59:44 pm
content: I understand the interrupt solution, but I haven't chosen it, not today :-) I do not say which is better or not, both can offer some advantages and disadvantages. I could possibly reimplement it as it'd be needed.Ok, DC removal possibly solved with this, what do you think?http://www.digitalsignallabs.com/dcblock.pdfBut still a curious question: Subtracting mean value out of the signal (moving averager with delay line, Fig 3A):What if I omit the delay line before the subtraction? (Phase will change, nonlinearly, possibly?)What if I replace the moving average with something like this (first order lowpass, exponential step response)?Code:out = (out*N + in) / (N+1)This is very easy to implement and ultrafast. No another circular buffering, as suggested in the pdf above.Or how do you solve the DC offset after the sqrt demodulator in your radios?

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 09:47:43 pm
content: Quote from: Yansi on June 14, 2015, 07:59:44 pmWith an AC coupling capacitor?More seriously, if you are already implementing a 300Hz to 3kHz BPF there should be no DC anyway.

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 09:54:29 pm
content: Quote from: Yansi on June 14, 2015, 07:35:24 pmWhy do you need a Hilbert transform if you already have the IQ from your Tayloe mixer?Lots of ways to do square roots, as you have probably found. Again, Richard Lyons' two books on DSP, the Understanding one and the Streamlining one will help here. The same goes for DC offsets, loads of suggestions in his books for that old chestnut, but I am not sure you need it if the signal is band limited already, and you are always taking the square root of the sum of two squares... ie, the argument to the square root is always going to be posiitive.

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 09:58:26 pm
content: OK, sorry, I misunderstood, the output of the square root, well yes, I'm afraid it is an AC coupling capacitor after all. Whether you use a DAC or PWM, unless the DAC is bipolar output, the old fashioned AC coupling cap will be the solution.

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 10:16:52 pm
content: You know... Hilbert is neccessary for SSB. I don't want to end with AM reception only. (or do I need it actually? with IQ signals?)In this setup there is only some filtering on the IQ signals. That won't cancel the dc after the sqrt no way. See the imgae below please.The square root returns positive numbers only corresponding to the input signal strength. The information is then superimposed on the DC. The DC should be equal to the signals idle level (without modulation) and needs to be subtracted.It is the same as with analog detector. At idle (without modulation) you will see a DC on the output. You then just AC couple the output of the rectifier circuit. The same happening in the DSP I think. And I am just questioning, how to remove the DC component in the DSP, If I'd set my mind not to use another FIR after the sqrt (which have also a limited suppresion of the DC).OK, then! But the cap after the DAC is a little ... eh... "solution" :-)If I'd need to implement a recording function in the radio, I'd still need to filter it. You don't want your wav with just too much offset.:-)

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 10:19:03 pm
content: No Hilbert is required for SSB if you have IQ already. The demodulation for SSB is _reallly_ simple compared to AM.

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 10:33:08 pm
content: Ok then. Simple enough. Saidly I have no reliable source of SSB signal here. Unfortunately my FT-225R has broken VFO (or the related PSU?) and needs repair. By using a downmixer (SAA602 or similar) it would have been used as a reference signal source...I have tried to build my own SW (80m band) QRPP DSB transmitter a few times, but none of them actually worked well. Always very bad carrier supression.

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 10:36:57 pm
content: Another bible for youhttp://www.arrl.org/files/file/Technology/tis/info/pdf/020708qex013.pdfhttp://www.arrl.org/files/file/Technology/tis/info/pdf/020910qex010.pdfhttp://www.arrl.org/files/file/Technology/tis/info/pdf/021112qex027.pdfhttp://www.arrl.org/files/file/Technology/tis/info/pdf/030304qex020.pdfThis, together with Rick Lyon's Understanding book, were the two primary texts I used when learning DSP. I had plenty of other texts, these were *by far* the most useful.The quadrature signals chapter from the Rick Lyons book is publicly reproduced here:http://dspguru.com/sites/dspguru/files/QuadSignals.pdfFor a signal source, do you have a canned oscillator, say 1MHz or so, or one you can divide down as necessary to the frequency of interest? But a couple of inches of wire on pin 3, it should be a very loud carrier.

author: Howardlong
author_rank: Super Contributor
timestamp: June 14, 2015, 10:40:34 pm
content: By the way, forgive my perhaps terse response about the Hilbert and SSB demodulation: I was trying help by giving you a bit of direction without actually giving you the answer :-)If you are stuck, let me know.

author: Yansi
author_rank: Super Contributor
timestamp: June 14, 2015, 10:50:13 pm
content: I am already reading/using the literature on this arrl site:http://www.arrl.org/software-defined-radioThe DSP Tutorial from Doug Smith KF6DX there is also very useful!The other pdf you sent (from Rick Lyon) - I am sure I have seen that - but silly me haven't saved the url, probably. Thanks!Yeah, a lot of canned XOs. By using another XO with 4*f a few kHz tweaked I could feed the Tayloe... that would work for a test! Thanks for the idea. Will test that soon.The only problem now is my free time, this week I will be probably very busy... but I am excited to test it.//No no not stuck yet. Your help is welcome. Now I have got I think most of the stuff I need for a quick test - except the HW. (It will take some time for parts to arrive and more time for the PCBs). I might quick-test it with a HCT4052. That must work too. And I think I have got also some better MUXes from Vishay or AD... Only need to find them.So I hacked up some basic schematic for the SDR AFE... It should work.. I hope. Luckily, the 14.318M crystal divided by 4 fits nicely inside the 80m band.Consider it "the first test ever", revision 0.

author: BFX
author_rank: Frequent Contributor
timestamp: June 15, 2015, 08:45:10 pm
content: http://www.ijera.com/papers/Vol4_issue4/Version%201/BM044394397.pdfhttp://www.google.sk/url?sa=t&rct=j&q=&esrc=s&source=web&cd=1&ved=0CB8QFjAAahUKEwihmdjPxJLGAhXJ0xQKHXaYAPE&url=http%3A%2F%2Felectronics.stackexchange.com%2Fquestions%2F16571%2Fsff-sdr-how-to-implement-a-simply-program-in-the-fpga&ei=OjV_VaGUJ8mnU_awgogP&usg=AFQjCNEX9S8bamDK-F-6zIXC7KYKsIXt7A&sig2=HR37Z-dSgu-rJrt3ryucQw&bvm=bv.95515949,d.bGQhttps://www.wpi.edu/Pubs/ETD/Available/etd-042711-091356/unrestricted/solivieri.pdf

author: Yansi
author_rank: Super Contributor
timestamp: June 15, 2015, 10:13:41 pm
content: Hi M.,thx 4 the links, but I can't get the relation. The topics discussed there are indeed interesting, unfortunately out of my scope. I can't do FPGAs well enough yet to try implementing such things. My skill with these devices is making a programmable counter/clock divider :-)So the first prototype board has been made. We'll se if it'll work a bit. Soon.

author: Yansi
author_rank: Super Contributor
timestamp: June 16, 2015, 01:50:11 pm
content: So there's the hardware. I´ve updated the schematic above to exatly match the hardware I've built:http://z56.imgup.net/IMG_360390bd.JPGNot pretty, I quite rushed with that thing.The 14.318M oscillator works just fine, so does the johnson counter.To test the HW, I've connected it to a PC soundcard. Software I use is SDR Sharp (SDR#).As a test signal source I've found my very old 3-transistor MW AM transmitter. The SDR is receiving on 14.318/4 = 3.579MHz. So I've tuned the transmitter to about 1.19MHz to receive the third harmonic, which is 3.567MHz - just 12kHz under the center frequency of the SDR.And it does receive. You can clearly see the sharp spike, which is the transmitter. But why's there the second mirrored spike? Shouldn't be there only one? The two are mirrored against the center. frequency. I think there should be visible only the left one spike. What's possibly wrong with it?The left one signal seems also a few dB stronger, than the right one. Swapping IQ signals does change the strength levels of the two spikes. So it is probably doing something, but why do I see the image frequency so strong?Thank you for your suggestions.

author: Kalvin
author_rank: Super Contributor
timestamp: June 16, 2015, 02:47:44 pm
content: Nice progress, Yansi.Does the amplitudes of the two spikes change as you change the TX frequency? If the I and Q signals suffer from phase and/or amplitude imbalance, this might show up as something like you are now seeing. Unfortunately I haven't bee playing with SDR, so I cannot be more specific here.

author: Yansi
author_rank: Super Contributor
timestamp: June 16, 2015, 03:18:47 pm
content: There might be something onto that. The SDR# software provides a selection of "IQ correction". I've switched that on and after a while the image peak slowly dissapeared, as it was integrating the phase and gain number (written in the window caption). It ended up somewhere about 1.4 gain imbalance and 30 to 40 degree correction. Interesting, mmm...So the HW impurities can be cleansed with some clever processing algorithms. (That I don't know, now). I think it'd be bettter to avoid problems dirrectly in the HW.So my first thought is: I've used quite regular SMD components with I think 5% resistance tolerance and standard ceramic caps with 5 or 10%. Nothing anywhere near perfect.The first thing which can distort phase in my circuit easily are the two caps in the feedbacks of the the opamps. I've put there quite large ones, to make the lowpass filter more filter stuff I don't want into the ADCs. So I'll try to remove them and use only decent one (a few hundred puffs at max). I will also change the feedback resistor, I will try to select two with matching resistance.Btw, if I tune the transmitter near the center frequency of the SDR, some other spikey thing starts coming up. That is also not probably good behavior:http://p06.imgup.net/asfdasdassdde3.pngAlready changed the caps and paired (they match good enough without any special selection) the resistors. It is a little better I think, but still I think too bad so one can't be satisfied. So lets hunt the error again. But where? Do you have any ideas?

author: Howardlong
author_rank: Super Contributor
timestamp: June 16, 2015, 06:18:54 pm
content: I would think that the IQ imbalance (which all analogue quadrature mixers have) is mostly due to the choice of relatively slow parts for both the switches and counter. I was thinking about mentioning this earlier, but I didn't want to put you off getting started on the hardware!10dB image isn't great, but as you've found SDR# does a reasonable job of correcting it.This is due to the phase and amplitude imbalance between the I and Q channels. Typically 40dB image rejection is a reasonable figure for this, so you still need to fix it in software.For a relatively narrow band such as yours this is achieved by a couple of constant multiplies and adds on the raw I and Q samples. Figuring out what those constants are is a little more complicated though! SDR# uses a stochastic method, it applies a few reasonably well chosen random values to one of the two constants and chooses the best one (by measuring the greatest power difference in the upper and lower FFT spectra). It then does the same with the second constant. It repeats the process iteratively, as the constants are not mutually exclusive. Nice and easy to do on an x86 where you're hardly short of power, not so much on an MCU, but still very feasible as a non-priority task.

author: Yansi
author_rank: Super Contributor
timestamp: June 16, 2015, 08:35:33 pm
content: Now I am listening to EA3JE from Barcelona, Spain. At 3,598MHz or thereabout. .. but he's off now.The SDR is indeed doing something, see how many stations I see in the 48kHz span. Unfortunately, the receiver has got low sensitivity, so I can barely understand what they are talking about. This capture is already with a two transistor preamp (20dB voltage gain) added on the input and of course with 3.rd order highpass filter, to get rid of that local three quarter megawatt middlewave transmitter.There is I think still something wrong with the HW: I've added a trimpot to on of the channel to finetune the gain. But it doesn't help a tiny bit to suppress the image.This is a revision zero hardware, better parts are already on their way. I contacted my HAM friends, I might borrow someone's already working SDR receiver so that I can focus on the software part.

author: Howardlong
author_rank: Super Contributor
timestamp: June 16, 2015, 10:26:42 pm
content: What's your antenna?

author: Yansi
author_rank: Super Contributor
timestamp: June 16, 2015, 11:27:44 pm
content: About 5 to 6 meters of untuned wire hanging in my room. Better than nothing. O0 (Usually enough for commercial receiver to get these strong stations without much strugle)

author: Yansi
author_rank: Super Contributor
timestamp: June 17, 2015, 02:19:03 pm
content: One thing is still not clear to me: Half a planet builds their SDRs like variant B. Two SPDT switches. I have based on the original publication from Dan Tayloe and made it like variant A (one SPQT switch). Is there anything wrong with variant A? Seems my SDR works no good, but others (with var. B) works quite well./* and also the Softrock SDRs use a C variant with a balanced transformer and only two sampling caps */And one other: Dan Tayloe in his publication successively simplifies the circuit, to reduce noise (less resistances in circuit). Why are most people using the circuits with so many resistors, and also artificially increasing switch resistance of the yet bad 4052/3? Like this for example:In my SDR, I have used the most simplified form from D.T. publ. - only single resistor in the opamp NFB, dc coupled to the sampling caps. Is there something dodgy that mostly everyone is avoiding this circuit?(The original paper:http://www.norcalqrp.org/files/Tayloe_mixer_x3a.pdf)

author: BFX
author_rank: Frequent Contributor
timestamp: June 17, 2015, 04:39:04 pm
content: Hi, try some magnetic loop antenna it's much better like your piece of wire.Also Mini Whip antenna is very good from my experience.

author: Yansi
author_rank: Super Contributor
timestamp: June 17, 2015, 05:01:42 pm
content: Lol, miniwhip is a minishit. Never been in a situation, where the miniwhip helped anything. (unless you want to amplify some noise)Magnetic loop should be better. Maybe I'll try to make a tuned loop antenna (don't know the exact name in English). That should do. Thanx for the idea.PS: Question about the Tayloe mix still remains :-)

author: BFX
author_rank: Frequent Contributor
timestamp: June 17, 2015, 07:03:10 pm
content: Quote from: Yansi on June 17, 2015, 05:01:42 pmI have Mini Whip for 3 years and often it's better than any from my 4 antennas(magnetic loop, dipole, Yagi and Mini Whip) of course for receiving.

author: Yansi
author_rank: Super Contributor
timestamp: June 17, 2015, 09:21:09 pm
content: Two new catches: ON7TQ Belgium (absolutely hilarious to listen to) and now DB2RR from Germany. O0No improvements in reception quality. The HW is faulty, somewhere.I've contacted a HAM friend, he lends mi his ADTRX-9 or DR2++ from Tasu YU1LM so I will have some reference receiver.

author: Kalvin
author_rank: Super Contributor
timestamp: June 17, 2015, 10:27:08 pm
content: Your op amp IC4A and IC4B + and - inputs impedanced are not matched ie. the - inputs contain 3k3 resistors connected to outputs and the + inputs doesn't have any resistors. Wild guess: Maybe those should be matched.

author: Yansi
author_rank: Super Contributor
timestamp: June 17, 2015, 10:46:02 pm
content: Might be. I simply copypasted the Tayloe's mixer circuit without much thougt, bcs I wanted the thought to go into the softwareIf think about what you suggests - the noninverting opamp input should have a restor to ground. Then it would make more sense. Solution simple: I'll add there the resistor. (equal to the NFB one). And let's see what it does. Stay tuned :-)And there's your problem. I've captured the IQ signal with a scope. Picture below. The blue one has got some weird shape and bigger amplitude. I can't balance it using the feedback resistor trimming. So I removed the opamp from the borad and measuring what is on the output of the mixer. Something is wrong with it. I'll find out what.

author: Kalvin
author_rank: Super Contributor
timestamp: June 18, 2015, 07:42:48 am
content: Quote from: Yansi on June 17, 2015, 10:46:02 pmAlthough the mixer is the most important part of the design which will ultimately determine the overall quality and performance of the receiverAnyway, you made good progess here. At least your project has been very educating and informative for me as well since I have only read with great interest about SDR during the last few years. When you get the mixer issues fixed, your should be able to make fast progress with the software. Don't get stuck with the mixer now, you can fix it later.

author: Kalvin
author_rank: Super Contributor
timestamp: June 18, 2015, 04:24:59 pm
content: Ps. Use C0G (NP0) capacitors in the signal path as those capacitors will not exhibit voltage dependent behaviour thus minimizing the distortion in the I and Q paths.

author: Yansi
author_rank: Super Contributor
timestamp: June 18, 2015, 04:49:48 pm
content: Thats a good remark. But C0G over 1nF are difficult to obtain I think. I have already thought about changing the sampling caps to MKS foil type, they also should have better match in capacity. That's as an enlightment for the next revision HW.But as I've already mentioned, I'll borrow a complete function SDR from a friend, so I can more focus on the firmware now. Sure, I can generate IQ signals directly via PC (I also will use that possibility for debugging the code), but that way I can't simulate the "real deal" sigals captured from air.I will also change the HC4052 chip, tommorow possibly. I've used some untested part from scrap PCB and I'm a little suspicious that the error might be also there. I've removed the OPAmp and the strange signal is directly after the MUX. The OPAmp wasn't faulty.By the way, has anyone tested, if the STM32F429 can deal the signal processing while driving a TFT (how large?) from SDRAM? I'm quite not sure how much impact that will have on the processing performance. The data between SDRAM and TFTshouldflow through an independent bus, itshouldn´tstall the buses CPU is using (FLASH, SRAM). Or I will just find out later...

author: Unknown
author_rank: Unknown
timestamp: June 19, 2015, 06:29:39 am
content: Quote from: Kalvin on June 18, 2015, 07:42:48 amA bigfrom me too - I've been meaning to build a Tayloe 'mixer' SDR for a while, but just haven't got around to it yet. I'm enjoying following this thread, and learning a lot. (And I had a feeling the imbalance problem would end up being a mixer issue...)

author: Yansi
author_rank: Super Contributor
timestamp: June 19, 2015, 07:26:30 am
content: The imbalance is the issue of the mixer, sure. But there some possibilities to work that out: Ultimately, you need all switches in the MUX with same resistance, the sampling caps should have the same capacity and the difference amplifiers should be balanced in gain (and phase). The mixer isn't obviously ideal, but I think using two LOs (sine and cosine) with two separate standard mixers like SA602 would be way more troublesome than this clever Tayloe mixer!As I know from a friend radioamateur who have built a lot of these SDRs with Tayloe mixers, the suppresion of the mirrored frequencies is in the range of 35 to 60dB, depending on how precisely you have tuned the circuit.My Tayloe mixer is somewhere crippled, it produces one signal heavily distorted and with strangle amplitude. Today I am on my way to buy new HC4052, bcs I couldn't trace that problem to any of the parts around the mixer, so the MUX itself may be at fault..... and I am also considering to build ADTRX-9 from YU1LM. It's quite nice construction and uses no special parts, only jellybean (I have them all in my shack), and is not much complicated to build (I guess about three afternoons for me).

author: Kalvin
author_rank: Super Contributor
timestamp: June 19, 2015, 07:45:43 am
content: One can also make phase/amplitude correction also in the digital domain. If i recall correctly, the STM32F4 chips contain options for audio signal generation, too. Just generate a known "training" signal and feed it to the I and Q inputs at the same time and create an adaptive FIR filter which will compensate and equalize the I and Q signals to match each other. This might be a bit advanced topic, but it is doable. I guess this is already implemented in SDR# software.You need to do this training only once and store the computed FIR coefficients. Once you know the equalization FIR coefficients, you can possibly tweak the decimation low-pass filter coefficients so that they will also include the correction. In this way, you have two filters in one, which will save cycles. And it would be a clever trick.

author: Yansi
author_rank: Super Contributor
timestamp: June 19, 2015, 08:12:21 am
content: I don't think the correction can be universal. From what I know from the SDR# software, the correction works correctly only on still signal input. Otherwise it doesn't do anything and slowly decays to gain and phase correction of somewhat zero.I think we should focus more on how to suppress the cause in the mixer rather than try to deal the result with software. The 16bit data precision is not much that precise and any additional computations will only bring up more noise I think. With all those multiplications and signal scaling for preventing overflows, the result is not that impressive as I think it should be.I am already using the rest of the FLASH (There is a whole 2Megabytes of it!) for storing a test signal. Now there's an audio track stored that I use to test the filters on, If I don't wan't an external audio source.

author: Kalvin
author_rank: Super Contributor
timestamp: June 19, 2015, 12:19:38 pm
content: Quote from: Yansi on June 19, 2015, 08:12:21 amThe correction is actually universal, as its sole purpose is to correct the amplitude and phase errors between the I and Q analog signal paths below Fs/2. The signal paths stay practically stable as the component values won't drift that much, but the initial component tolerances cause imbalance between the I and Q analog paths, as you have already observed. With the equalizer that imbalance between the I and Q analog paths can be corrected. After correction the I and Q signal paths will be very close to identical and the Tayloe detector will perform well.The I and Q analog filters' relative amplitude and phase errors will typically be quite modest at the lower frequencies (mostly amplitude error which is quite easy to compensate), but the relative amplitude and phase errors due to component tolerances will increase heavily as the frequency components approach to 3dB corner frequency.Of course, you should try to build the analog signal paths as good as possible in the first place, and after that you might want to try to improve the SDR's performance even more using the equalizer.

author: Howardlong
author_rank: Super Contributor
timestamp: June 19, 2015, 02:35:06 pm
content: I discussed the method SDR# uses to determine the correct gain and phase correction herehttps://www.eevblog.com/forum/projects/digital-clock-source-for-simple-diy-sdr-radio-with-tayloe-mixer/msg694724/#msg694724There isn't a way to do this analytically as far as I can tell, there was a paper about six or seven years ago that claimed it could be done that way but I found an error in it which was fundamental, and the author agreed.So you're stuck with numerical methods.The imbalance correction includes both gain and phase components. Together with DC correction, you apply this to each sample:I += IDCCorrQ += QDCCorrQ = (Q + ( I * PhaseCorr) ) * GainCorrWith PhaseCorr initialised to 0 and GainCorr initialised to 1, and adjusted as necessary.

author: Kalvin
author_rank: Super Contributor
timestamp: June 19, 2015, 03:52:05 pm
content: Howardlong, thanks.I was thinking more of a brute-force method using adaptive FIR with LMS-algorithm, similar to used in baseband modems using the cpper wires: When the connection is being established, the transmitter sends a certain period of known pseudo-random signal. The receiver will reveice the signal and adjust its receive FIR equalizer so that the signal quality is as good as possible. As the transmitter will always transmit a known sequence of data, the receiver knows what to expect and it is very straight-forward to compute the error estimate for the LMS-algorithm. The STM32F4 has DAC-output which could be used for injecting the training signal into I and Q analog paths at the same time and the DSP software would compute necessary corrections for the I and Q equalizers.Your solution is simple and fast, and it should work pretty well. If I understood correctly, Yansi might want decimate I and Q signals, so the I and Q signals' higher frequency components - where the phase starts changing rapidly - will be discarded anyway.

author: Yansi
author_rank: Super Contributor
timestamp: June 21, 2015, 08:14:34 pm
content: Hi guys, sorry, I've been busy a while.I've started to build a nice and well proven HW for my SDR toying. I am bulding ADTRX-9 from YU1LM. I really don't like the way the board was done Eagle, but the component layout is kind of good. Important is, that the device was successfuly tested by many people, so it should work.The ADTRX-9 should let me also transmitt (it is a transceiver, ofcourse), nice kit for my needs now. It is not done yet, I am working on the transmitting path now. The receiving art is already working. Unfortunately, same problems with mirrored signal rejection. Only the same 10dB. The outputs were checked and precisely set to equal amplitude. The phase also looks good. So I'm quite suspicious, that the soundcard in my PC may be at fault.If I let the SDR# do its job, it finds a correction phase of somwhere about 50 degrees, while leaving the gain almost 1. I suspect that antialiasing filters on the soundard (old SB Live!) are different in phase, so the signal gets corrupted this way. Or where the big 50 degree error should rise? I quite don't understand that phenomenon. What do you think?Here's how my unfinished ADTRX9 looks like:

author: Unknown
author_rank: Unknown
timestamp: June 22, 2015, 06:09:09 am
content: Quote from: Yansi on June 21, 2015, 08:14:34 pmFrom memory at least one version* of the SB Live! cards did alternate-channel sampling at higher sample rates (above 24 or 32k, can't remember) - resulting in a 1/2 sample delay between channels. Could it be due to that? If you can squeeze your signal into the right place, try reducing the sample rate to 16k (e.g. 8kHz bandwidth) & see if the problem disappears.(* Creative were notorious for producing cards of the same name & model with wildly different chipsets depending on when they were built.)

author: Howardlong
author_rank: Super Contributor
timestamp: June 22, 2015, 06:48:14 am
content: Quote from: Tac Eht Xilef on June 22, 2015, 06:09:09 amYou are right. Trying to correct for IQ imbalance across the band in these circumstances is a fruitless exercise unless one uses frequency dependent correction. Some years ago I had a PCMCIA SB card that did exactly this, bloody expensive it was too, it took a long time for me ti figure out what the problem was.

author: Kalvin
author_rank: Super Contributor
timestamp: June 22, 2015, 08:40:02 am
content: Quote from: Howardlong on June 22, 2015, 06:48:14 amOne could try to use fractional interpolation or decimation filter, which should be suitable in the situations like this. Simplest solution is of course fix the problem in the hardware and get a soundcard with appropriate simultanous sampling.For the someone interested in the subject, here is quite practical paper for engineers familiar with the DSP "Splitting the Unit Delay" (ok, quite math-intensive but almost comprehensible):http://home.agh.edu.pl/~turcza/sr/Splitting%20the%20Unit%20Delay.pdfAssociated Matlab source code:http://legacy.spa.aalto.fi/software/fdtools/

author: eduardoG26
author_rank: Newbie
timestamp: April 18, 2016, 03:39:26 pm
content: Hallo Yansi.I don't know if you are still interested in your SDR design.There is most probably a problem with connecting the inverting inputs of the OpAmps without resistors.Check other Tayloe designs, as NC2030 f. e.Good luck.Eduardo

author: Yansi
author_rank: Super Contributor
timestamp: April 30, 2016, 09:58:47 am
content: Thank you for your tip, the NC2030 seems to be a very nice piece of kit. I could not find the whole schematic of it, but have found some building manual where the mixer schematic is (attached below).Again, interesting why there is 200+ MHz opamp ?! Just playin why?Yes am still interested in some SDR design experimenting, but currently no free time for that. Planning to resume the project in summer.

author: chris_leyson
author_rank: Super Contributor
timestamp: April 30, 2016, 10:29:11 am
content: I found that using the right analog switch for a mixer makes a big difference to phase noise performance. You need low "ON" resistance and fast switching speed to get the mixer noise figure down.

author: Yansi
author_rank: Super Contributor
timestamp: April 30, 2016, 10:50:33 am
content: Noise was the last issue with my experimental setup. The main issue was it was doing absolutely nothing.I have tried with 74HC4000 series MUX, but I have already bought a bunch of Pericom PI3B3253 switches. They are fast as a whipsnap, while havin pretty low ON resistance... (The type Tayloe used in his original design).

author: timofonic
author_rank: Frequent Contributor
timestamp: May 01, 2016, 02:00:30 am
content: How does this work with GNU Radio?

author: Yansi
author_rank: Super Contributor
timestamp: May 06, 2016, 10:34:26 am
content: Pardon, how does what work with what? To which post is your post related to?

author: Yansi
author_rank: Super Contributor
timestamp: June 09, 2016, 10:56:50 pm
content: Finally got some spare time to make some small progress. This time, I studied (again) the basics of a SSB demodulation in a DSP.This document describes very nicely all basic operations needed:https://www.arrl.org/files/file/Technology/tis/info/pdf/98qex003.pdfSo I know, I need a Hilbert transform, to shift the Q signal another 90 degrees. (Note: Fine, I found myself a little tool from "Iowa Hills" which can do the thing as expected. Here are their very neat tools:http://www.iowahills.com/8DownloadPage.html)So basically I need two lowpass filters, for I and Q baseband signal. And a third one, the hilbert transformer, to be able to demodulate the SSB. However the document above mentions(page 13, "Analythic Filter-pair Synthesis"), that the baseband filter coefficients may be modified by multiplying the impulse response with a complex exponential. Thus reducing the need for the third FIR, keeping only the two modified response ones.That seemed interesting optimization. So I tried to test the theory in matlab. My limited understanding of that technique is that I will get two filters, with thesamemagnitude response and phase different by 90degree between the two filters. However the results from matlab do tell otherwise.I have written a simple script, which generates a set of coefficients for a lowpass FIR filter. Then I try to applyEquation 43from the document above to produce two sets of new coefficients for the modified filters. I did assume, that the multiplication by complex exponential will only result in shifting the filter's original passband, as the omega_0 changes. In reality, the passband just sits at half the nyquist frequency and changes its passband width in the case of a Q-filter, the I-filter does move the slope a bit, but has completely different magnitude response.I have attached the matlab code and a few screenshots of the results. It is weird, I might be doing something wrong. Can you help please?

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2016, 06:50:41 pm
content: Some advice, not all directly related to your question, sorry, but I can't help myselfDon't use j as a variable. MATLAB allows j or i as sqrt(-1) but this will eventually bite you when you can't figure out why a script isn't working, and then you realize it's because you redefined sqrt(-1) into something else. (You probably shouldn't use i as a variable either but as we all know j is the true sqrt(-1)!)Try to define vectors and use ".*" to multiply element-by-element. Much easier then loops.MATLAB is the only place in the known universe with their weird definition of frequency. Keep sane by using "digital frequency" f = freq_in_Hz / sampling_freq_in_Hz such that 1/2 == Nyquist and follow that convention everywhere, only multiplying by two when you need to use a MATLAB function that thinks 1 == Nyquist. Of course some people prefer omega too. Personally I find it much easier to think in digital [non-angular] frequency and throw in the 2*pi factor wherever I need it.Now to the stuff that might actually help... To keep things simple, make your LPF with an odd number of taps. Call this L. Then in MATLAB-speak,M = (L-1)/2; % this is the filter ordern = [-M:M];hi = h .* cos(2*pi*fc*n); % where fc = desired center frequency / sampling frequencyhq = h .* sin(2*pi*fc*n);BTW any linear-phase FIR filter of "type 3" or "type 4" automatically has the hilbert-transforming property. That's basically what we're doing when we multiply by sin(2*pi*fc*n), changing from even-symmetric to odd-symmetric at the same time we shift the center frequency away from DC.Instead of calling fir1 you could do the window design yourself and just specify both filters directly, ashi = 2*B*sinc(B*n) .* hamming(L)' .* cos(2*pi*fc*n);hq = 2*B*sinc(B*n) .* hamming(L)' .* sin(2*pi*fc*n);where L, n, and fc are defined above and B is the desired bandwidth, again in proper normalized units of (true bandwidth / sampling frequency). This is probably the best way to gain insight into what you are doing. (B*sinc(B*n) gives a perfect brick-wall, unity-gain response if n goes on forever, but of course we are truncating it, so we multiply point-by-point with a window function to reduce the sidelobes at the expense of a less-sharp filter, then we modulate from DC to fc by multiplying point-by-point with 2*cos() or 2*sin().I didn't delve too deeply into your script, but I suspect one of the problems is your LPF bandwidth is too wide and/or you are not modulating the filter far enough in frequency. Remember that multiplication by a real sinusoid produces two copies in the spectral domain, one shifted up and the other shifted down. (Also remember that freqz is only showing you the positive frequencies; the LPF extends the same distance in negative frequency.) If you don't shift far enough, the two copies pile up and interfere with one another. So, the half-band LPF you've designed has a cutoff at 0.25 (I am using proper/correct frequency units here, so 0.25 == halfway to Nyquist). The width of that LPF is 0.5 if you measure its full extent in +/- frequency. When you modulate it you can just barely avoid a spectral collision if you use fc=0.25 (multiply by cos(2*pi*n*0.25)): One copy will be centered at 0.25 and the other at -0.25. This will be essentially an all-pass filter because each copy will span from 0 to 0.5 (or -0.5). Of course, that may be exactly what you want for your SDR.

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2016, 06:52:19 pm
content: PS Don't learn MATLAB. Learn Numpy/Scipy instead. But if you do learn MATLAB, follow my advice above

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2016, 07:19:45 pm
content: Yansi:If you are demodulating with IQ from a Tayloe or other quadrature downconverter, then you won't need a Hilbert transformer.One other point, personally I found Doug Smith's articles to be really difficult as an introduction to DSP: they tend to be very math(s) heavy, and theoretical with no practical examples. If you're good at dealing with abstract concepts in maths and engineering then that's fine but I find his articles (and his book) to be very hard going.The alternatives that I found invaluable are:o Gerald Youngblood's articles starting herehttps://www.arrl.org/files/file/Technology/tis/info/pdf/020708qex013.pdfo Rick Lyons' Understanding Digital Signal ProcessingI also use Excel extensively and Octave as a Matlab alternative.

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2016, 07:32:21 pm
content: Quote from: Howardlong on June 10, 2016, 07:19:45 pmAdmittedly it has been a while since I played with it, but I don't think this is right. He's trying to demodulate SSB. Assuming you start with I and Q baseband signals as every comms text defines them, he's doing the right thing. You may be thinking of "how to get the Q signal" which would involve a separate Hilbert transformer, if the downconversion didn't already provide quadrature outputs.

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2016, 08:17:53 pm
content: You only need the Hilbert to emulate the quadrature signal. So if you already have the I & Q there's no need for a Hilbert transformer.Edit: I am assuming low IF, take a look here, at figure 4.http://www.microwavejournal.com/articles/3226-on-the-direct-conversion-receiver-a-tutorialThe main reason to avoid zero IF is any DC offset an LO phase noise present in analogue downconverters, but it's also handy for allowing you to use a quadrature NCO in software to to your demodulation.

author: mark03
author_rank: Frequent Contributor
timestamp: June 10, 2016, 09:51:29 pm
content: OK but the OP is trying to receive a single-sideband signal. You have two real baseband signals, i(n) and q(n). How do you combine them to obtain the demodulated audio?See e.g. Figure 11 here:https://www.dsprelated.com/showarticle/176.php

author: Howardlong
author_rank: Super Contributor
timestamp: June 10, 2016, 11:22:11 pm
content: Ok, but assuming the OP is using an analogue downconverter (as the title and content of the posts suggest) I can't really recommend trying to demodulate at zero IF mixed in the analogue domain primarily due to the phase noise and DC offset complications around zero Hz.This is why typical narrowband SSB implementations operate a second IF in software, say at 10kHz or so, perfoming identical dual channel filtering, second quadrature down conversion, and AGC all in the digital domain. The result is that the USB is simply calculated as I+Q and the LSB is I-Q, and you can avoid the Hilbert transform altogether and those nasty zero IF artefacts.The reason I'm saying this is that I too got wound up some years ago into thinking I needed to use the HT, and became fixated on them when I really didn't need them, possibly as a result of reading texts such as Doug Ford's. In practice I've found them usually (but not always) unnecessary, and that they often add unnecessary confusion and complexity.While Doug Smith's texts are, I am sure, of value to some, I just found that they had too much maths and too little real practical application, almost written as a supporting text for people who already know the answer, if that makes sense.Edit: typos

author: coppice
author_rank: Super Contributor
timestamp: June 11, 2016, 04:06:51 pm
content: Quote from: Yansi on June 09, 2016, 10:56:50 pmIf you actually require a second 90 degree shift, why would you use something as complex as a Hilbert transform to get it? You have the I signal. Just invert it and you have your 90 + 90 degree shifted signal.

author: seriouscoinage
author_rank: Contributor
timestamp: June 12, 2016, 01:13:06 am
content: That's not going to work. Adding I to an inverted version of itself will result in nothing. Adding/subtracting I to Q shifted by another 90degrees yields the portion of the frequency spectrum either above or below the mixer frequency.edit: In general, a phase inversion is not the same thing as a phase shift.

author: coppice
author_rank: Super Contributor
timestamp: June 12, 2016, 08:44:10 am
content: Quote from: seriouscoinage on June 12, 2016, 01:13:06 amEr, yeah, I probably shouldn't post when half asleep.

author: Yansi
author_rank: Super Contributor
timestamp: June 12, 2016, 09:49:25 am
content: I've been always told also, that "phase inversion" is a nonsense. Phase can not be inverted. Polarity can be.I am quite lost in your explanations. Do I need hilbert transform or not to demodulate SSB from I and Q signal? (Is it needed to shift the Q another 90 degrees with hilbert?)

author: Kalvin
author_rank: Super Contributor
timestamp: June 12, 2016, 11:18:54 am
content: Take a look at this. Quite a simple and straightforward design:https://www.tapr.org/pdf/DCC2010-simpleSDR-KF6SJ.pdfAlthough using PSoc3 as the implementation platform, the principles stay the same independent of your hardware.Here is another design using PSoc5 for SSB and AM:http://pa0rwe.nl/?page_id=32You can extract quite a lot of useful information from those projects.

author: Yansi
author_rank: Super Contributor
timestamp: June 12, 2016, 11:37:07 am
content: Thank you, I need Hilbert transform on the Q path, or the analytic filter pair (which I have failed to produce).I think I have seen the Psoc3 project some time ago. Notice the opamp circuit after the mixer, seems there might be a mistake: If the opamp is supposed to work as a differential amp (which I think it is supposed to), then the + leg misses the matching resistor divider.//From such projects it seems diy SDR is very doable... kind of like a motivation to do it. But I am still doing more wrong than good.

author: seriouscoinage
author_rank: Contributor
timestamp: June 13, 2016, 02:44:31 am
content: I think there are two main ways to do SSB demodulation, from what I have read. Seehttp://michaelgellis.tripod.com/mixerscom.html. There is a phasing method, using the Hilbert transform, and the "Weaver method," which does not. With the phasing method:Apply quadrature mixing to RF signal, mixing it down to baseband (direct conversion)Convert IQ channels to digitalApply Hilbert transform to Q channelTake sum or difference of I and Q to get USB or LSBWith the Weaver methodApply quadrature mixing to RF signal, mixing it a low IF (e.g. 10kHz)Convert IQ channels to digitalApply digital filter to IQ to select USB or LSBMix IQ channels with a complex exponential down to basebandTake sum/difference of I and Q to get baseband signal, which is either +/- 10kHz of the mixer frequency

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2016, 10:27:15 am
content: Thank you for explanation. The first method is that one I know from the QEX article. The second seems interesting, but also more computation hungry.The frequency translation (using a complex exponential) seems to be mandatory anyway, if I'd like to finetune the reception frequency. So the second "weaver method" might be also possible.Unfortunately, I need to get some f*king HW going first, haven't got much luck last time. Now, I equipped myself with some better parts, like better multiplexers (FST3253, PI3B3253). Still I don't know, what purpose or performance effect has the bandwidth of the OPAmp after the mixer. Usually, people use very fast and expensive opamps there, like 200MHz BW or so, even that the bandwidth is limited to a few tens of kHz. Interestingly, the SDR project using the PSOC chip uses only a half decent opamp with 20MHz BW.I should probably now draw some new version of schematic and consult it with you, to make some progress.

author: Howardlong
author_rank: Super Contributor
timestamp: June 13, 2016, 10:57:25 am
content: Quote from: seriouscoinage on June 13, 2016, 02:44:31 amClose, but not quite, you choose USB or LSB by choosing the the sum or the difference, not by using a filter. Here's a practical scheme:o Downconvert RF to quadrature I/Q low IF in the analogue/hardware domain with LO 12kHz above or below target freq.o Filter both channels with a 24kHz analogue LPF on each channel.o Convert resulting I & Q channels to digital domain (2 x simultaneous sampling ADCs @ 48kSa/s *** each)o Complex multiply with a quadrature NCO running at 12kHz to give digitally downconverted basebando Take either I+Q or I-Q depending on whether you want USB or LSB **o Apply a single 3kHz LPF to the sum or difference created in the previous stepo Apply an AGC as necessaryo Send to your preferred audio device** For AM, take sqrt(I^2 + Q^2).... yes, USB and LSB is easier to demodulate than AM!***strictly speaking for this scheme you could reasonably sample at, say, 24kSa/s as you're discarding potential aliased frequencies in the later 3kHz LPF anyway, but also 48kSa/s is a very common sampling rateEdit: no, I was thinking about this, because you wouldn't have much luck trying to make a 12kHz quadrature NCO with a sampling rate of 24kSa/s. 48kSa/s it is.By using a low IF, the filters are kept reasonable simple and not too compute intensive as the cutoffs are in the same order of magnitude as the sampling rate.

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2016, 11:37:14 am
content: So here's the schematic v2.0 I could come up with. I will no longer use that simplified nonsense with opamp inputs directly on the mixer filter caps. I'll use the classic differential circuit. (That way I can be sure, it will work). The mixer is biased through an RF choke and resistor. I have used only the unbalanced input version, will connect both halves of the PI3B3253 in parallel to lower the switch impedance even more. (Yes, no longer 74HC4052).I think there should be also a set of resistors in series with the switches, to linearize the switches and to better define the the mixer cutoff frequency. (From the input impedance and switch series impedance) the filter caps C could be calculated. The value of the series resistors I've seen is usually between 10 to 33ohms.Also the only thing why to use a high GBW opamp there I can think of is to have butter commonmode rejection at HF. Is that right?Another change from the previous circuit is here's no input amplifier. The last one worked more like an attenuator than amplifier. But would be actualy nice to have there some input amp and possibly also a filter (at least some lowpass). :-/Can you please check and verify the schematic? Any suggestions will be welcome!Thx, Yan

author: seriouscoinage
author_rank: Contributor
timestamp: June 13, 2016, 12:33:32 pm
content: Quote from: Howardlong on June 13, 2016, 10:57:25 amThis makes a little more sense than what I was thinking. I was thinking that you should apply a bandpass filter before complex multiplying to select the USB/LSB relative to the IF frequency (or select the AM signal,) but this filter is more complex than a LPF applied at baseband.

author: Yansi
author_rank: Super Contributor
timestamp: June 13, 2016, 08:00:53 pm
content: A little update:Few days ago, first important part for an SDR system was made fully functional: The AD/DA audio codec. In January, I have designed a simple board to test the codec (Wolfson WM8731), but I've had a lot of other work to do, so just on friday evening, I started to assemble the board and Saturday about lunch, it was fully working, filtering an audio signal with some biquad filters.Here's the result. The ugly board with three pots is to control the PEQ programmed in (frequency, Q, gain).Now I need working LO and the mixer. Could you please review the schematic above, if you see there any mistakes or problems?

author: seriouscoinage
author_rank: Contributor
timestamp: June 14, 2016, 12:33:17 am
content: Looking at your schematic, it looks correct. The GBW of the op-amps does in theory restrict CMRR at high frequencies, but I think the matching of your resistors is more likely to be the limit on the circuit's CMRR. The speed of the op-amps will restrict the effectiveness of the LPF they implement at high frequencies, though. I have read that some op-amps have nonlinear behaviour with higher frequencies:http://electronicdesign.com/analog/op-amp-audio-realizing-high-performance-bandwidth-limitations. This is my biggest concern about using a low GBW op-amp - if e.g. a strong out-of-band AM signal reaches your op-amp input, it might be detected by the nonlinear op-amp input and turn up as audio interfering with your baseband signal.In a few days I should be able to put together my own Tayloe detector board, and I'll make a post or thread about it - whether it works or not, perhaps it will help you design yours.

author: seriouscoinage
author_rank: Contributor
timestamp: June 18, 2016, 12:01:05 pm
content: I hope I'm not hijacking your thread Yansi, but I got my Tayloe mixer working and thought it might be helpful to you. It is pretty similar to most other circuits on the web, with an Si570 feeding a Johnson counter which drives a CBT3253 switch, but it uses in-amps at the output. The antenna I am using currently is a very poor indoor one, so I can only pick up quite strong signals, but the circuit otherwise seems to work well. In retrospect the circuit probably doesn't need these fairly expensive in-amps, but I think an in-amp arrangement of some sort is a good choice for getting the differential signal.

author: Yansi
author_rank: Super Contributor
timestamp: June 18, 2016, 05:18:21 pm
content: Hmm, seems working. What is the image rejection? And why does the switch has different bias, than the opamps? (not in the middle of the VCC)

author: seriouscoinage
author_rank: Contributor
timestamp: June 20, 2016, 09:58:52 am
content: Image rejection is just under 50dB, using a sine wave from my signal generator. This isn't too bad, but could be better. I think the most obvious source of imbalance is the gain setting resistors for the inamps - they are just ordinary 1% resistors, and I made no effort to match them. This can easily be fixed in software though. (I tried checking the IQ correction checkbox in SDR Sharp, but it didn't seem to do anything.) I was able to make a crude active loop antenna, which I put up to my window, and I'm getting some more signals now. This circuit really wants a preselector - I am getting lots of signals on the 3rd harmonic of the LO frequency, and lots of AM broadcast breakthrough (this *might* actually be the active loop antenna, though.)

author: Howardlong
author_rank: Super Contributor
timestamp: June 20, 2016, 11:09:53 am
content: 50dB is very reasonable for most analogue quadrature mixers, there's probably not much point trying to polish that any more, environmental effects such as temperature will start to become significant.I am pretty familiar with the way the IQ image correction works in SDR Sharp, I did some work with the author of the software as well as doing my own IQ correction algorithms. I can assure you that it isn't "easily fixed in software", it is actually quite complex to get it right. It is not solvable analytically, you have to use numerical methods.SDR sharp uses a stochastic method, i.e., it makes random attempts to correct for phase and amplitude channel mismatch, takes an FFT, and then correlates the effects of the guesses on upper and lower sidebands, maximizing the aggregated power delta between opposite FFT bins. Over time, the more guesses make for better image rejection.The method I used is similar, but it's iterative rather than stochastic, narrowing down phase and gain imbalance successively. While this attains the imbalance match more quickly it's a bit harder to implement.If you're unable to get a balance, then whatever you're using to sample might not be simultaneously sampling. There have been instances of sound cards sampling 1 sample out on the left channel to the right channel which is impossible to correct for with I/Q imbalance correction alone.

author: chris_leyson
author_rank: Super Contributor
timestamp: June 20, 2016, 11:23:42 am
content: 50dB image rejection is quite respectable, I think 1% amplitude error or 1 degree phase error will give you 40dB image rejection, ball park figure. I quite like the Tayloe mixer architecture, it's a re-arrangement of the quad fet mixer but with all the sources tied to ground some you don't get gate source intermod effects.

author: seriouscoinage
author_rank: Contributor
timestamp: June 20, 2016, 11:41:27 am
content: Quote from: Howardlong on June 20, 2016, 11:09:53 amWhen I said "easily fixed in software," I was specifically talking about any gain imbalance, which I thought should be simple to fix by just multiplying one channel by a constant - I didn't mean to imply that IQ correction is easy in general. I suppose if the SDR Sharp IQ correction doesn't do anything, then there must not be much gain imbalance anyway. I wouldn't be surprised if the imbalance was due to something the soundcard was doing - it's just whatever audio codec is an old computer's motherboard. In any case, 50dB is good enough for now. It's good to get some info from someone with more experience with SDR - I'm pretty new to all of this.Quote from: Yansi on June 18, 2016, 05:18:21 pmI forgot to answer your question about the switch bias - with a 5V supply, the AD8421's common mode range is not centered on 2.5V, it is closer to 3V. The common mode range is also rather small. This doesn't seem to have caused any problems so far, but if I designed this again I would probably try a different approach than the in-amp ICs.One approach I was thinking about was to simply avoid differential-to-single-ended conversion altogether. Have a preselector filter in the front end, followed by a LNA to provide any gain required and provide a 50ohm output for the mixer. Then the mixer outputs could be connected directly to a differential input audio ADC, possibly with an LC antialiasing filter in between. The only problem I can think of is that there might be problems with the LNA's nonlinearity, but I think the preselector should help with that. Are there any problems I'm missing with this approach?

author: Howardlong
author_rank: Super Contributor
timestamp: June 20, 2016, 12:44:30 pm
content: If you're going to have to do gain and phase corection in software anyway, then I don't see a lot of point in doing it in hardware unless you're trying to diagnose something else.Typically the correction calculation itself is done by a couple of multiplies and an add to the streaming IQ signal: the difficulty is in calculating those fudge factors automatically!If you are writing the software yourself, then you might want to try doing it manually with a couple of sliders on a UI to apply the coefficients, for example:IOut = IinQOut = (QIn + (IIn * k1) ) * k2starting with k1=0 and k2=1. These two coefficients have interaction between them on the image rejection, so you need to repetitively adjust one then the other.These will only correct for frequency indepedent errors. If there is a frequency dependent correction required then it's quite a bit more complicated, but typically for soundcard based SDR the above is easily good enough, with 90dB+ of image rejection achievable.

author: Yansi
author_rank: Super Contributor
timestamp: June 20, 2016, 04:00:32 pm
content: Thank you guys for some more valuable discussion. Those correction algorithms might be tried also, if I ever get the basics working. Unfortunately, again I've been doing different things and am currently outta any free time. :-(seriouscoinage, if you happen to build the next version with gain concentrated in an RF LNA, could you please share the design with us? Any schematic for inspiration would be very helpful for me. Thanks.Yan

author: eduardoG26
author_rank: Newbie
timestamp: June 01, 2017, 08:21:33 am
content: My suggestion:Take a cheap board called "ELEKTOR SDR reloaded"(german ELEKTOR 2016/7) designed by B. Kainka.It contains a SI5351, Tayloe Mixer, Opamps, Filtering and plugs on any Arduino or STM32 nucleo.Start of with arduino example sketch and roll your own SW on STM32 using IAR EWB f. e.Good luck!

author: cdev
author_rank: Super Contributor
timestamp: June 05, 2017, 02:46:14 am
content: If you ever return to this project, you can use a number of SDR programs - particularly Linrad, as a test bench of sorts to evaluate the I and Q output, even if the software cant talk directly to the hardware (to tune the LO, for example).

author: Yansi
author_rank: Super Contributor
timestamp: June 12, 2017, 03:55:44 pm
content: Thanks for a tip. I would like to definitely return to this project before the end of this summer, however I have got a difficult situation in here with family and jobs, so not much free time for toying. If I have to do electronics, it is mostly if not always for $$$. But I'll see how it'll go this summer.Y.

author: cdev
author_rank: Super Contributor
timestamp: September 14, 2017, 08:14:25 pm
content: You probably figured this out ages ago but a (resonant) magnetic loop, is a preselector and a very good one. If you havent already, ditch the active preamp and use a simple tuned circuit which can developseveral voltsat its output with a strong signal.Back in the day they used to connect them to a diode and earphone and call it a receiver, look ma, no batteries.Try that to give your SDR more sensitivity and especially, selectivity.PM me if you want tips,this article has a bunch of great loop coupling ideas.Whats the cheapest AM shortwave band receiver that could be built using an STM32 and a minimum of other parts?

author: Yansi
author_rank: Super Contributor
timestamp: September 15, 2017, 11:56:46 am
content: There were no problems getting RF signal, I could plug in an LO directly. There was problem to make the stupidly simple Tayloe mixer to work reasonably. Maybe I will return to that and try again. Or maybe not, I will find a proper way to do it, instead of using cheepium MUXes that need 4f LO to work.

author: cdev
author_rank: Super Contributor
timestamp: September 15, 2017, 01:02:09 pm
content: Is it possible to simulate the external hardware to chop up the signal in the STM32's own logic? When I say cheap I mean really cheap. See the thread I posted about a contest in the General Chat area. Basically I am wondering if its possible to make a tiny cheap shortwave receiver out of just an STM32 and a minimum of other parts (a few pushbuttons, maybe some varactor enabled circuitry to interface with a short piece of wire to provide an automatically tuned magnetic loop to improve selectivity and image rejection.I have found that cheap SDRs work extremely well with a "hot" very high "Q" magnetic loop, Far better than with any other antenna. This can be shown graphically by using screenshots of the waterfall display using traditional antennas vs. high-q magloop.You can use an AB antenna switch and switch between the two, its quite useful to compare them that way.) Size is an issue, antenna has to be very small so it can be concealed -People should consider that lots of poor people around the world have no access to a computer but would very much like to have a simple, tiny shortwave radio that could run on very low power and offer basic AM functionality up to around 20 MHz.Especiallly people in North Korea where all tunable radios are illegal and large radios are much more likely to be found than small.Radio often is what people sane. But to be caught with one can often be a life altering (or ending) experience. So the smaller the better.Smaller, cheaper good radios would save lives.Seehttps://www.theguardian.com/global/2016/aug/27/north-korea-defectors-ian-birrellalso seeThe Wall Which Crumbles: North Korea and the Outside Worldhttp://raskb.com/transactions/VOL86/VOL86-3.docx(this is a very good essay on the information blockade around North Korea)also:http://www.intermedia.org/wp-content/uploads/2013/05/A_Quiet_Opening_FINAL_InterMedia.pdfSee also:http://www.psr.org/assets/pdfs/two-billion-at-risk.pdfThe cost of inaction could be very very high

author: Yansi
author_rank: Super Contributor
timestamp: September 15, 2017, 05:26:35 pm
content: I have no intents designing a HF radio for North Koreans. I do not wish these guys anything bad, but the sole purpose of this thread was I think different.To answer your question: Some STM32s are equipped with multiple ADCs capable of reaching sample rates of up to about 10Msps when interleaved sampling is used, so direct reception of the LW, MW and lower SW signals might be possible.You do not need a separate I and Q basebands to be able to work with the signal digitally, you can direct sample the RF signal and then produce the I and Q by multiplying the signal with complex exponential e^i*2*pi*f*t. The unknown in this case is, if the MCU is fast enough to do this. I know about some shortucts to do this already an think it may be possible to do with reasonable performance. Maybe I should try that? All in all I wanted to tinker with the DSP algorithms any way...

author: cdev
author_rank: Super Contributor
timestamp: September 15, 2017, 05:54:25 pm
content: I do too, the Tayloe mixer is a brilliant design. plus the utter cheapness of the STM32 - combined with its amazing ADC functionality just begs the question, can it be done.