Hi,
Apologies for the delayed response to this.
I asked this question to several people who were / are involved with the creation and maintenance of this worker / component.These are their responses, which I have slightly edited to fix formatting and remove names, etc.
I hope the formatting is retained or this might be quite hard to read :D
--- First Response ---
This is explained in the documentation:
However, the term carrier_amplitude may be misleading, carrier_gain would be better.
In (9) we are looking to define the gain A for some given complex sample - the gain is relative to the input so we consider the input on a unit circle, i.e. x and y are in the range -1 to 1.
Substituting in (9) for the point where the term multiplying A is maximal (x = x_max and y = -x_max):
A ( x_max * cos (theta) – (-x_max) * sin( theta) )
----------------------------------------------------------------- < x_max
2^15
As x_max is 1 and the largest value of cos(theta) + sin(theta) is sqrt(2) we then get:
A * sqrt(2)
-------------- < 1
2^15
Solving for A:
A * sqrt(2)
-------------- = 1
2^15
A * sqrt(2) = 1 * 2^15 = 2^15
A = 2^15 / sqrt(2) = 23170.475….
A is scaled by 1.64…. and so carrier_amplitude should be set to 14070 for a gain of 1 through the component.
However, the underlying cordic can over/under-shoot so we recommend using the value 14,060.
There is (in my opinion) an unnecessary limitation in the C++ implementation which sets an upper bound of the carrier_amplitude value to 14,060 – it is perfectly reasonable to use this component as a gain block – i.e. setting the value to 28,000 would double the output amplitude relative to the input.
(if you consider the input to be half scale (x = 0.5, y = 0.5, x_max = 1) and substitute in (9) you get 28,140).
I did test the RCC implementation and the above holds, I believe the RCC and HDL implementations are both tested against the same Python based model – so have no reason to expect the HDL version is any different.
--- Second Response ---I have been doing some thinking on this also and I think I see what Dan is getting at…but also understand why it is designed as is.
The issue Dan is bringing up is specifically with this bit -> “A is maximal (x = x_max and y = -x_max)”. If the carrier mixer input is a “perfect” iq tone, as it is in Dan case, with sin and cos waveforms 90 degrees apart the condition “x = x_max and y = -x_max” never occurs (see below that there is never a point in time where x is 1 and y is 1 (or -1)).
Euler’s formula is the easiest way to understand this (I reckon…):
When frequency shifting, Dan wants to realise the below formula, where
is the input signal and
is the generated signal.
However, what is currently done is an acknowledgment that the input waveform might not be a “perfect” since wave and therefore is accounting for the “x = x_max and y = -x_max)” condition occurring.
So the
term is reduced to
, since the magnitude of
gives 1, which ensures whatever the input is there is no overflow. To be clear, the
is
and
(the amplitude of the generated waveform).
In summary, I think how we have it implemented now is correct since it ensures a messy input waveform never overflows on the output when it is mixed. But a good compromise to allow for Dan’s “perfect” input waveform use case is as the first reply says: adding the ability to set the carrier_amplitude to a value such that an amplitude of 32767 instead of 23170 is achieved for the generated waveform.
I will relay this information onto the ocpi.comp.sdr developers to add to their backlog.
---
I hope this was helpful.
Kind Regards,
Dom WaltersOn Wed, Jan 24, 2024 at 4:22 PM <dwp@md1tech.co.uk> wrote:Hi,
I want to use the carrier_mixer_us in
ocpi.comp.sdr.dspcomponent to down convert a signal.Ideally I would want the input wave to have the same amplitude as the output wave however this does not seem to be possible due to the
carrier_amplitudeproperty having a maximum allowed value of 14,060.Since the property is scaled by 1.646760258, this brings the amplitude of the mixer wave to 23170.475 or roughly sqrt(2) * 2^15. I would understand if the amplitude was limited to 2^15 to prevent overflow but what is the reason for this sqrt(2) factor?
Before outputting, the result of each multiplication is shifted right by 15 (both I and Q) i.e scaled by 1 / 2^15. Therefore with the maximum mixer amplitude, the resulting wave’s amplitude will be roughly 1/sqrt(2) that of the input wave.
It is also quite counterintuitive that the input amplitude of the carrier wave is being scaled this way. Would it not be possible to provide the true amplitude to the
carrier_amplitudeproperty and have the worker do the necessary scaling? If not, renaming the property to indicate that it is not the actual amplitude would be useful.Thanks,
_______________________________________________
Dan
discuss mailing list -- discuss@lists.opencpi.org
To unsubscribe send an email to discuss-leave@lists.opencpi.org