Fixed-point representation is commonly used in applications where fractional precision is required but the overhead of floating-point arithmetic is undesired.
The range of fixed-point numbers is determined by the number of bits allocated for both the integer and fractional parts of the representation.
It's important to understand that fixed-point numbers have a limited precision and range compared to floating-point numbers.
The Q notation defined by Texas Instruments is the letter Q followed by a set of numbers m.n. where m is the number of bits used for the integer part of the value and n is the number of decimal point bits. By default, this notation represents signed binary fixed-point format, and unscaled integers are stored in the two's complement format used by most binary processors.
The first bit always indicates the sign of the value (1 = negative, 0 = non-negative) and is not counted by the m parameter. Therefore, the total number of bits used w is 1 + m + n.
If m is 0, all bits except the sign bit are fractional bits.
For example, Q0.15 describes a signed fixed-point number with w = 1+0+15 = 16 bits. That is, it is a 16-bit signed two's complement integer.
Scaling involves multiplying the integer value by a scaling factor to accurately represent fractional values.
The Q15 format is a fixed-point representation used in digital signal processing. In this format, numbers are represented with 16 bits, where 1 bit is allocated for the sign and 15 bits for the fractional part. For Q15 representation, the range of values that can be represented is from -1 to (1 - 2^(-15)), inclusive. This corresponds to -1.0 to 0.99997 in decimal notation. In decimal form, the range of Q15 representation is approximately -1.0 to 0.99997.
To convert a fraction to Q0.15 format in C, you need to scale the fraction by 2^15 and then cast it to a 16-bit integer. Here's a simple C code snippet to demonstrate this conversion:
#include <stdio.h>
#define Q15_SCALE_FACTOR (1 << 15)
int main()
{ double fraction = 0.75; // Example fraction to convert
// Convert fraction to Q0.15 format
int q15_value = (int)(fraction * Q15_SCALE_FACTOR);
// Print the result
printf("Fraction %.2f in Q0.15 format: %d\n", fraction, q15_value);
return 0;
}
This code first defines a macro Q15_SCALE_FACTOR representing 2^15. Then, it multiplies the input fraction by this scaling factor and casts the result to an integer, effectively converting it to Q0.15 format.
To retrieve the fractional number from a value represented in Q0.15 format in C, you need to divide the integer value by the scaling factor (2^15). Here's the C code to achieve this:
#include <stdio.h>
#define Q15_SCALE_FACTOR (1 << 15)
int main()
{ int q15_value = 49152;
// Example Q0.15 value to convert back to fraction
// Retrieve fractional number from Q0.15 format
double fraction = (double)q15_value / Q15_SCALE_FACTOR;
// Print the result printf("Q0.15 value %d converted back to fraction: %.4f\n", q15_value, fraction);
return 0;
}
In this code, the Q0.15 value is divided by the scaling factor (2^15), and the result is cast to a double to obtain the fractional number.
TODO: how to convert between different q formats, for example when u get energy from samples, you need not signed notation because energy is always postv.
Also suppose you collected the IQ samples in Q0.15 but at point of the signal processing chain, you do not need that much accuracy, so how do you extract the MSB.
Q15 ranges from -32768 to 32767 with a granularity of 1/32768.
Overflow occurs when the result exceeds 32767 and underflow occurs when results goes below -32768.