Message ID | 1418635162-8814-2-git-send-email-prladdha@cisco.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Hi, Sharing the patches towards some improvements in sine generation. This was one of the item in to-do list for vivid. Vivid generates a frequency modulated (FM) signal (I and Q components) for SDR. FM signal is generated by varying the phase in proportion to input signal. Basically it is implementing FM by doing a phase modulation. It was reported that on SDR receiver, when the sine signal is recovered after demodulation, the quality of tone is cracky. Looking at time and frequency plot of the signal recovered after demodulation, I found that sine wave discontinuous and frequency spectrum was spread out a lot. Based on my discussion with Hans and Antti, there were two suspected reasons 1. Rounding errors in calculations 2. The equation used to compute modulated signal. Please find the patches for - 1. Use look up table (LUT) for computing (co)sine values (patches 1 to 4) This will replace Taylor series based computation. LUT based implementation for (co)sine calculation have following advantages - a. Rounding errors would be less. b. One could easily control and improve the precision of calculation c. Computationally more efficient 2. Increase precision of calculation (patch 5) Use higher precision for sine LUT as well as all other calculations (phase values etc). 3. Modify equation used to generate sample for frequency modulated wave (patch 6) Please review these patches and share your comments. I will share the time, frequency plots for signal seen before and after the proposed improvements. Thanks to Hans and Antti for helping me to understand the problem and later reviewing the solution for it. Regards, Prashant -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Em Mon, 15 Dec 2014 14:49:17 +0530 Prashant Laddha <prladdha@cisco.com> escreveu: > Replaced Taylor series calculation for (co)sine with a > look up table (LUT) for sine values. Kernel has already a LUT for sin/cos at: include/linux/fixp-arith.h The best would be to either use it or improve its precision, if the one there is not good enough. Regards, Mauro > > Also reworked fixed point implementation to reduce rounding errors. > > Cc: Hans Verkuil <hans.verkuil@cisco.com> > Cc: Antti Palosaari <crope@iki.fi> > Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com> > > Signed-off-by: Prashant Laddha <prladdha@cisco.com> > --- > drivers/media/platform/vivid/Makefile | 2 +- > drivers/media/platform/vivid/vivid-sdr-cap.c | 87 ++++++------- > drivers/media/platform/vivid/vivid-sin.c | 184 +++++++++++++++++++++++++++ > drivers/media/platform/vivid/vivid-sin.h | 31 +++++ > 4 files changed, 252 insertions(+), 52 deletions(-) > create mode 100644 drivers/media/platform/vivid/vivid-sin.c > create mode 100644 drivers/media/platform/vivid/vivid-sin.h > > diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile > index 756fc12..9d5fe1c 100644 > --- a/drivers/media/platform/vivid/Makefile > +++ b/drivers/media/platform/vivid/Makefile > @@ -2,5 +2,5 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ > vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ > vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ > vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ > - vivid-osd.o vivid-tpg.o vivid-tpg-colors.o > + vivid-osd.o vivid-tpg.o vivid-tpg-colors.o vivid-sin.o > obj-$(CONFIG_VIDEO_VIVID) += vivid.o > diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c > index 4af55f1..1f8b328 100644 > --- a/drivers/media/platform/vivid/vivid-sdr-cap.c > +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c > @@ -31,6 +31,7 @@ > #include "vivid-core.h" > #include "vivid-ctrls.h" > #include "vivid-sdr-cap.h" > +#include "vivid-sin.h" > > static const struct v4l2_frequency_band bands_adc[] = { > { > @@ -423,40 +424,17 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) > return 0; > } > > -#define FIXP_FRAC (1 << 15) > -#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) > - > -/* cos() from cx88 driver: cx88-dsp.c */ > -static s32 fixp_cos(unsigned int x) > -{ > - u32 t2, t4, t6, t8; > - u16 period = x / FIXP_PI; > - > - if (period % 2) > - return -fixp_cos(x - FIXP_PI); > - x = x % FIXP_PI; > - if (x > FIXP_PI/2) > - return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); > - /* Now x is between 0 and FIXP_PI/2. > - * To calculate cos(x) we use it's Taylor polinom. */ > - t2 = x*x/FIXP_FRAC/2; > - t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; > - t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; > - t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; > - return FIXP_FRAC-t2+t4-t6+t8; > -} > - > -static inline s32 fixp_sin(unsigned int x) > -{ > - return -fixp_cos(x + (FIXP_PI / 2)); > -} > - > void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) > { > u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); > unsigned long i; > unsigned long plane_size = vb2_plane_size(&buf->vb, 0); > - int fixp_src_phase_step, fixp_i, fixp_q; > + int fixp_i, fixp_q; > + > + u32 adc_freq; > + u32 sig_freq; > + s32 src_phase_inc; > + s32 mod_phase_inc; > > /* > * TODO: Generated beep tone goes very crackly when sample rate is > @@ -466,34 +444,41 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) > > /* calculate phase step */ > #define BEEP_FREQ 1000 /* 1kHz beep */ > - fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, > - dev->sdr_adc_freq); > + > + adc_freq = dev->sdr_adc_freq; /* samples per sec*/ > + sig_freq = BEEP_FREQ; /* cycles per sec */ > + src_phase_inc = phase_per_sample(sig_freq, adc_freq); > > for (i = 0; i < plane_size; i += 2) { > - dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); > - dev->sdr_fixp_src_phase += fixp_src_phase_step; > > - /* > - * Transfer phases to [0 / 2xPI] in order to avoid variable > - * overflow and make it suitable for cosine implementation > - * used, which does not support negative angles. > - */ > - while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) > - dev->sdr_fixp_mod_phase += (2 * FIXP_PI); > - while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) > - dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); > + mod_phase_inc = calc_cos(dev->sdr_fixp_src_phase); > + dev->sdr_fixp_src_phase += src_phase_inc; > + > + while (dev->sdr_fixp_src_phase >= ((44 << FIX_PT_PREC)/7)) > + dev->sdr_fixp_src_phase -= ((44 << FIX_PT_PREC)/7); > + > + mod_phase_inc <<= FIX_PT_PREC; > + mod_phase_inc /= 1275; > + > + dev->sdr_fixp_mod_phase += mod_phase_inc; > + > + while (dev->sdr_fixp_mod_phase < 0) > + dev->sdr_fixp_mod_phase += ((44 << FIX_PT_PREC) / 7); > > - while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) > - dev->sdr_fixp_src_phase -= (2 * FIXP_PI); > + while (dev->sdr_fixp_mod_phase >= ((44 << FIX_PT_PREC) / 7)) > + dev->sdr_fixp_mod_phase -= ((44 << FIX_PT_PREC) / 7); > > - fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); > - fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); > + fixp_i = calc_sin(dev->sdr_fixp_mod_phase); > + fixp_q = calc_cos(dev->sdr_fixp_mod_phase); > > /* convert 'fixp float' to u8 */ > - /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ > - fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; > - fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; > - *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); > - *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); > + /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] > + The values stored in sin look table are pre-multipied with 1275. > + So, only do addition */ > + > + fixp_i += 1275; > + fixp_q += 1275; > + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, 10); > + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, 10); > } > } > diff --git a/drivers/media/platform/vivid/vivid-sin.c b/drivers/media/platform/vivid/vivid-sin.c > new file mode 100644 > index 0000000..e3d6149 > --- /dev/null > +++ b/drivers/media/platform/vivid/vivid-sin.c > @@ -0,0 +1,184 @@ > +/* > + * vivid-sin.c - software defined radio support functions. > + * > + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights > + * reserved. > + * > + * This program is free software; you may redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND > + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS > + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN > + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN > + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE > + * SOFTWARE. > + */ > + > +#include <linux/errno.h> > +#include <linux/kernel.h> > + > +#include "vivid-sin.h" > + > +#define SIN_TAB_SIZE 256 > + > + /*TODO- Reduce the size of the table */ > +/* Since sinewave is symmetric, it can be represented using only quarter > + of the samples compared to the number of samples used below */ > + > +static s32 sin[257] = { > + 0, 31, 63, 94, 125, 156, 187, 218, > + 249, 279, 310, 340, 370, 400, 430, 459, > + 488, 517, 545, 573, 601, 628, 655, 682, > + 708, 734, 760, 784, 809, 833, 856, 879, > + 902, 923, 945, 965, 986, 1005, 1024, 1042, > + 1060, 1077, 1094, 1109, 1124, 1139, 1153, 1166, > + 1178, 1190, 1200, 1211, 1220, 1229, 1237, 1244, > + 1251, 1256, 1261, 1265, 1269, 1272, 1273, 1275, > + 1275, 1275, 1273, 1272, 1269, 1265, 1261, 1256, > + 1251, 1244, 1237, 1229, 1220, 1211, 1200, 1190, > + 1178, 1166, 1153, 1139, 1124, 1109, 1094, 1077, > + 1060, 1042, 1024, 1005, 986, 965, 945, 923, > + 902, 879, 856, 833, 809, 784, 760, 734, > + 708, 682, 655, 628, 601, 573, 545, 517, > + 488, 459, 430, 400, 370, 340, 310, 279, > + 249, 218, 187, 156, 125, 94, 63, 31, > + 0, -31, -63, -94, -125, 156, -187, -218, > + -249, -279, -310, -340, -370, -400, -430, -459, > + -488, -517, -545, -573, -601, -628, -655, -682, > + -708, -734, -760, -784, -809, -833, -856, -879, > + -902, -923, -945, -965, -986, -1005, -1024, -1042, > + -1060, -1077, -1094, -1109, -1124, -1139, -1153, -1166, > + -1178, -1190, -1200, -1211, -1220, -1229, -1237, -1244, > + -1251, -1256, -1261, -1265, -1269, -1272, -1273, -1275, > + -1275, -1275, -1273, -1272, -1269, -1265, -1261, -1256, > + -1251, -1244, -1237, -1229, -1220, -1211, -1200, -1190, > + -1178, -1166, -1153, -1139, -1124, -1109, -1094, -1077, > + -1060, -1042, -1024, -1005, -986, -965, -945, -923, > + -902, -879, -856, -833, -809, -784, -760, -734, > + -708, -682, -655, -628, -601, -573, -545, -517, > + -488, -459, -430, -400, -370, -340, -310, -279, > + -249, -218, -187, -156, -125, -94, -63, -31, > + 0 > + }; > + > +/* > + * Calculation of sine is implemented using a look up table for range of > + * phase values from 0 to 2*pi. Look table contains finite entries, say N. > + * > + * Since sinusoid are periodic with period 2*pi, look table stores entries > + * for phase values from 0 to 2*pi. > + * > + * The interval [0,2*pi] is divided into N equal intervals, each representing > + * a phase increment of (2*pi/N) > + * > + * The index 'n' in look up table stores sine value for phase (2*pi*n/N) as - > + * sin_tab[N] = {sin(0), sin(1*(2*pi/N)),sin(2*(2*pi/N)), ..., sin(N*(2*pi/N))} > + * > + |---------|---------|---------|---- . . . .|---------| . . . . |---------| > + 0 (2*pi/N) (2*2*pi/N) (3*2*pi/N) (n*2*pi/N) 2*pi > + * > + * Generation of sine waveform with different frequencies - > + * > + * Consider a sine tone with frequency 'f', so, > + * num_cycles_per_sec = f > + * Let sampling frequency be 'Fs' so, > + * num_samples_per_sec = Fs > + * So, num_samples_per_cycle = Fs/f > + * Let Nc = Fs/f > + * > + * That is, number of samples during one interval of 0 tp 2*pi = Nc, each > + * sample represents a phase increment of (2*pi/Nc = 2*pi*f/Fs). > + * > + * So, for "k" th sample the phase, phi = k*(2*pi/Nc) > + * > + * The sine value at phase increments of (2*pi / Nc) is calculated by > + * interpolating two adjecent samples from sine look table > + * > + * As an example, sine value for phase (phi) is calculated below > + * > + * 1. Find the interval [(n*2*pi/N), ((n+1)*2*pi/N)] to which phi belongs > + > + * 0 (2*pi/N) (n*2*pi/N) ((n+1)*2*pi/N) 2*pi > + * |---------| . . . . . |---------|---------| . . . . . |---------| > + * ^ > + * d0-- > | < --d1 > + * | > + * phi = k*(2*pi/Nc) > + * > + * For phase (phi) the index n in sine table is given by (phi)/(2*pi/N) > + * n = integer part of ( phi / (2*pi / N) ) > + * > + * 2. Find distance d0 and d1 using fractional arithmatic. > + * d0 = phi - n*(2*pi / N), > + * d1 = 2*pi / N - d0 > + * > + * 3. The calculations of fractions are done using fixed point implementation > + * > + * 4. To improve the precision of fixed point implementations, divisions > + * in different calculations are delayed till last operations. Say, > + * d0 = phi - n*(2*pi / N) > + * d0 = phi - n * (2 * (22 / 7) / N) , substitute pi = 22 / 7 > + * d0 = phi - (n * 44 * N) / 7 > + */ > +s32 calc_sin(u32 phase) > +{ > + u32 index; > + u32 d0; > + u32 d1; > + s32 result; > + u64 temp0; > + u64 temp1; > + > + temp0 = phase * SIN_TAB_SIZE; > + index = (temp0 * 7) / (44 << FIX_PT_PREC); > + > + temp0 = (temp0 * 7) / 44; > + temp1 = index << FIX_PT_PREC; > + > + d1 = temp0 - temp1; > + d0 = (1 << FIX_PT_PREC) - d1; > + > + result = (d0 * sin[index % 256] + d1 * sin[(index+1)%256]); > + > + return result >> FIX_PT_PREC; > +} > + > +s32 calc_cos(u32 phase) > +{ > + u32 index; > + u32 d0; > + u32 d1; > + s32 result; > + u64 temp0; > + u64 temp1; > + > + temp0 = phase * SIN_TAB_SIZE; > + index = (temp0 * 7) / (44 << FIX_PT_PREC); > + > + temp0 = (temp0 * 7) / 44; > + temp1 = index << FIX_PT_PREC; > + > + d1 = temp0 - temp1; > + d0 = (1 << FIX_PT_PREC) - d1; > + > + index += 64; > + result = (d0 * sin[index % 256] + d1 * sin[(index+1)%256]); > + > + return result >> FIX_PT_PREC; > +} > + > +u32 phase_per_sample(u32 signal_freq, u32 sampling_freq) > +{ > + /* phase increment or decrement with each sample is given by > + * (2 x Pi x signal frequency)/sampling frequency > + * To get a better accuracy with fixed point implementation we use > + * Pi = 22/7 > + * */ > + u64 temp = 44 * ((u64)signal_freq << FIX_PT_PREC); > + > + return temp / (7*sampling_freq); > +} > diff --git a/drivers/media/platform/vivid/vivid-sin.h b/drivers/media/platform/vivid/vivid-sin.h > new file mode 100644 > index 0000000..6c8bab2 > --- /dev/null > +++ b/drivers/media/platform/vivid/vivid-sin.h > @@ -0,0 +1,31 @@ > +/* > + * vivid-sin.h - support functions used to generate (co)sine waveforms for > + * software defined radio. > + * > + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights > + * reserved. > + * > + * This program is free software; you may redistribute it and/or modify > + * it under the terms of the GNU General Public License as published by > + * the Free Software Foundation; version 2 of the License. > + * > + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, > + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF > + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND > + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS > + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN > + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN > + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE > + * SOFTWARE. > + */ > + > +#ifndef _VIVID_SIN_H_ > +#define _VIVID_SIN_H_ > + > +#define FIX_PT_PREC 16 > + > +s32 calc_sin(u32 phase); > +s32 calc_cos(u32 phase); > +u32 phase_per_sample(u32 signal_freq, u32 sampling_freq); > + > +#endif -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
On 12/15/2014 03:13 PM, Mauro Carvalho Chehab wrote: > Em Mon, 15 Dec 2014 14:49:17 +0530 > Prashant Laddha <prladdha@cisco.com> escreveu: > >> Replaced Taylor series calculation for (co)sine with a >> look up table (LUT) for sine values. > > Kernel has already a LUT for sin/cos at: > include/linux/fixp-arith.h > > The best would be to either use it or improve its precision, if the one there > is not good enough. I looked that one when made generator. It has poor precision and it uses degrees not radians. But surely it is correct practice improve existing than introduce new. regards Antti
Antti, Mauro, Thanks for your comments. On 15/12/14 7:00 pm, "Antti Palosaari" <crope@iki.fi> wrote: >On 12/15/2014 03:13 PM, Mauro Carvalho Chehab wrote: >> Em Mon, 15 Dec 2014 14:49:17 +0530 >> Prashant Laddha <prladdha@cisco.com> escreveu: >> >>> Replaced Taylor series calculation for (co)sine with a >>> look up table (LUT) for sine values. >> >> Kernel has already a LUT for sin/cos at: >> include/linux/fixp-arith.h >> >> The best would be to either use it or improve its precision, if the one >>there >> is not good enough. Thanks. I had not looked at this file earlier. But now when I looked at this file I agree with Antti¹s comments below. > >I looked that one when made generator. It has poor precision and it uses >degrees not radians. > Also, it does not support calculation for phase values falling in middle of two entries of LUT. >But surely it is correct practice improve existing >than introduce new. I agree. Probably we can start looking into how to improve existing. I looked at dependancies. As of now functions in fixp-arith is used by two other files. Replacing current implementation in fixp-arith.h with high precision will not work as it is, because caller functions are using lesser precision. We probably need to discuss more on how to improve existing implementation. Some thoughts - 1. Going by the name fixp-arith.h, I feel, it should have larger scope than just (co)sine implementation. It can include divide as well. One could also consider option to keep all trignometric functions in another file 2. One could support APIs to provide output with different precisions, say 16, 32, 64 bits etc. Not sure how final implementation would be but one option would be to do internal computation with highest precision possible and then truncate the result to have desired precision based on the API called. Regards, Prashant
Em Tue, 16 Dec 2014 06:41:18 +0000 "Prashant Laddha (prladdha)" <prladdha@cisco.com> escreveu: > Antti, Mauro, > > Thanks for your comments. > > On 15/12/14 7:00 pm, "Antti Palosaari" <crope@iki.fi> wrote: > > > >On 12/15/2014 03:13 PM, Mauro Carvalho Chehab wrote: > >> Em Mon, 15 Dec 2014 14:49:17 +0530 > >> Prashant Laddha <prladdha@cisco.com> escreveu: > >> > >>> Replaced Taylor series calculation for (co)sine with a > >>> look up table (LUT) for sine values. > >> > >> Kernel has already a LUT for sin/cos at: > >> include/linux/fixp-arith.h > >> > >> The best would be to either use it or improve its precision, if the one > >>there > >> is not good enough. > > Thanks. I had not looked at this file earlier. But now when I looked at > this file I agree with Antti¹s comments below. > > > > > >I looked that one when made generator. It has poor precision and it uses > >degrees not radians. > > > > Also, it does not support calculation for phase values falling in middle > of two entries of LUT. > > > >But surely it is correct practice improve existing > >than introduce new. > > I agree. Probably we can start looking into how to improve existing. I > looked at dependancies. As of now functions in fixp-arith is used by two > other files. Replacing current implementation in fixp-arith.h with high > precision will not work as it is, because caller functions are using > lesser precision. We probably need to discuss more on how to improve > existing implementation. if you do a: $ git grep -e 'sin(' --or -e 'cos(' You'll notice that there are other drivers that have also their own sin()/cos() needs, with their own implementation. I'm not saying we should touch them, but it is worth to check what are their needs, in order to be sure that whatever we do would latter fit on their usages. > Some thoughts - > 1. Going by the name fixp-arith.h, I feel, it should have larger scope > than just (co)sine implementation. It can include divide as well. One > could also consider option to keep all trignometric functions in another > file We could do that, but let's start with sin/cos functions. Btw, there are log implementation functions already at dvb-core at drivers/media/dvb-core/dvb_math.[ch] Those are also candidates to be moved to a more generic place. > 2. One could support APIs to provide output with different precisions, say > 16, 32, 64 bits etc. Not sure how final implementation would be but one > option would be to do internal computation with highest > precision possible and then truncate the result to have desired precision > based on the API called. Internally, I would stick with a 32 bits implementation, where the 1.0 would mean S32_MAX. 64 bits is likely an overkill, and would be slower on 32 bits machines. Using degrees also seem to be a good thing, as the table will be symmetric, and the 90th value will be equal to 1.0 (for a sin table). That means that we need an array with just 90 elements instead of 256. To be generic enough, the logic should use modulus math, to be sure that the given value will be converted into an angle between 0 and 360, and then down-converted to 0-90, in order to use a table with just a quarter of the values, e. g. something like: static inline const s32 sin_table[] = { 0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c, 0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd, 0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e, 0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44, 0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb, 0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1, 0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04, 0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82, 0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039, 0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879, 0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf, 0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af, 0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884, 0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095, 0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e, 0x7fffffff }; s32 fixp_sin32(int value) { s32 ret; bool negative = false; value = (value % 360 + 360) % 360; if (value > 180) { negative = true; value -= 180; } if (value > 90) value = 180 - value; ret = sin_table[value]; return negative ? -ret : ret; } And then define the 16 bits and cos() variants for it with: #define fixp_cos32(v) fixp_sin32((v) + 90) #define fixp_sin16(v) (fixp_sin32(v) >> 16) #define fixp_cos16(v) (fixp_cos32(v) >> 16) If we end latter to need 64 bits, it shouldn't be hard to change the logic there to add a different table. Regards, Mauro -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Em Tue, 16 Dec 2014 08:45:53 -0200 Mauro Carvalho Chehab <mchehab@osg.samsung.com> escreveu: > Em Tue, 16 Dec 2014 06:41:18 +0000 > "Prashant Laddha (prladdha)" <prladdha@cisco.com> escreveu: > > > Antti, Mauro, > > > > Thanks for your comments. > > > > On 15/12/14 7:00 pm, "Antti Palosaari" <crope@iki.fi> wrote: > > > > > > >On 12/15/2014 03:13 PM, Mauro Carvalho Chehab wrote: > > >> Em Mon, 15 Dec 2014 14:49:17 +0530 > > >> Prashant Laddha <prladdha@cisco.com> escreveu: > > >> > > >>> Replaced Taylor series calculation for (co)sine with a > > >>> look up table (LUT) for sine values. > > >> > > >> Kernel has already a LUT for sin/cos at: > > >> include/linux/fixp-arith.h > > >> > > >> The best would be to either use it or improve its precision, if the one > > >>there > > >> is not good enough. > > > > Thanks. I had not looked at this file earlier. But now when I looked at > > this file I agree with Antti¹s comments below. > > > > > > > > > >I looked that one when made generator. It has poor precision and it uses > > >degrees not radians. > > > > > > > Also, it does not support calculation for phase values falling in middle > > of two entries of LUT. > > > > > > >But surely it is correct practice improve existing > > >than introduce new. > > > > I agree. Probably we can start looking into how to improve existing. I > > looked at dependancies. As of now functions in fixp-arith is used by two > > other files. Replacing current implementation in fixp-arith.h with high > > precision will not work as it is, because caller functions are using > > lesser precision. We probably need to discuss more on how to improve > > existing implementation. > > if you do a: > $ git grep -e 'sin(' --or -e 'cos(' > > You'll notice that there are other drivers that have also their own > sin()/cos() needs, with their own implementation. > > I'm not saying we should touch them, but it is worth to check what are > their needs, in order to be sure that whatever we do would latter fit > on their usages. > > > Some thoughts - > > 1. Going by the name fixp-arith.h, I feel, it should have larger scope > > than just (co)sine implementation. It can include divide as well. One > > could also consider option to keep all trignometric functions in another > > file > > We could do that, but let's start with sin/cos functions. Btw, there are > log implementation functions already at dvb-core at > drivers/media/dvb-core/dvb_math.[ch] > > Those are also candidates to be moved to a more generic place. > > > 2. One could support APIs to provide output with different precisions, say > > 16, 32, 64 bits etc. Not sure how final implementation would be but one > > option would be to do internal computation with highest > > precision possible and then truncate the result to have desired precision > > based on the API called. > > Internally, I would stick with a 32 bits implementation, where the 1.0 would > mean S32_MAX. 64 bits is likely an overkill, and would be slower on 32 bits > machines. > > Using degrees also seem to be a good thing, as the table will be symmetric, > and the 90th value will be equal to 1.0 (for a sin table). > > That means that we need an array with just 90 elements instead of 256. > To be generic enough, the logic should use modulus math, to be sure that > the given value will be converted into an angle between 0 and 360, and > then down-converted to 0-90, in order to use a table with just a quarter > of the values, e. g. something like: > > static inline const s32 sin_table[] = { > 0x00000000, 0x023be165, 0x04779632, 0x06b2f1d2, 0x08edc7b6, 0x0b27eb5c, > 0x0d61304d, 0x0f996a26, 0x11d06c96, 0x14060b67, 0x163a1a7d, 0x186c6ddd, > 0x1a9cd9ac, 0x1ccb3236, 0x1ef74bf2, 0x2120fb82, 0x234815ba, 0x256c6f9e, > 0x278dde6e, 0x29ac379f, 0x2bc750e8, 0x2ddf003f, 0x2ff31bdd, 0x32037a44, > 0x340ff241, 0x36185aee, 0x381c8bb5, 0x3a1c5c56, 0x3c17a4e7, 0x3e0e3ddb, > 0x3fffffff, 0x41ecc483, 0x43d464fa, 0x45b6bb5d, 0x4793a20f, 0x496af3e1, > 0x4b3c8c11, 0x4d084650, 0x4ecdfec6, 0x508d9210, 0x5246dd48, 0x53f9be04, > 0x55a6125a, 0x574bb8e5, 0x58ea90c2, 0x5a827999, 0x5c135399, 0x5d9cff82, > 0x5f1f5ea0, 0x609a52d1, 0x620dbe8a, 0x637984d3, 0x64dd894f, 0x6639b039, > 0x678dde6d, 0x68d9f963, 0x6a1de735, 0x6b598ea1, 0x6c8cd70a, 0x6db7a879, > 0x6ed9eba0, 0x6ff389de, 0x71046d3c, 0x720c8074, 0x730baeec, 0x7401e4bf, > 0x74ef0ebb, 0x75d31a5f, 0x76adf5e5, 0x777f903b, 0x7847d908, 0x7906c0af, > 0x79bc384c, 0x7a6831b8, 0x7b0a9f8c, 0x7ba3751c, 0x7c32a67c, 0x7cb82884, > 0x7d33f0c8, 0x7da5f5a3, 0x7e0e2e31, 0x7e6c924f, 0x7ec11aa3, 0x7f0bc095, > 0x7f4c7e52, 0x7f834ecf, 0x7fb02dc4, 0x7fd317b3, 0x7fec09e1, 0x7ffb025e, > 0x7fffffff > }; > > s32 fixp_sin32(int value) > { > s32 ret; > bool negative = false; > > value = (value % 360 + 360) % 360; > if (value > 180) { > negative = true; > value -= 180; > } > if (value > 90) > value = 180 - value; > > ret = sin_table[value]; > > return negative ? -ret : ret; > } > > And then define the 16 bits and cos() variants for it with: > > #define fixp_cos32(v) fixp_sin32((v) + 90) > #define fixp_sin16(v) (fixp_sin32(v) >> 16) > #define fixp_cos16(v) (fixp_cos32(v) >> 16) > > If we end latter to need 64 bits, it shouldn't be hard to change > the logic there to add a different table. Forgot to mention, but it could make sense to have a version that would allow more than 360 values for the angle. We can do that via linear interpolation. Something like (untested): #define INT_2PI ((s32)(2 * 3.141592653589 * 32768.0)) static inline s32 fixp_sin32_rad(u32 radians) { int degree; s32 v1, v2, dx, dy; u64 tmp; degree = (radians * 360) / INT_2PI; v1 = fixp_sin32(degree); v2 = fixp_sin32(degree + 1); dx = INT_2PI / 360; dy = v2 - v1; tmp = radians - (degree * INT_2PI) / 360; tmp *= dy; do_div(tmp, dx); ret (s32)(v1 + tmp64); } Regards, Mauro -- To unsubscribe from this list: send the line "unsubscribe linux-media" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
diff --git a/drivers/media/platform/vivid/Makefile b/drivers/media/platform/vivid/Makefile index 756fc12..9d5fe1c 100644 --- a/drivers/media/platform/vivid/Makefile +++ b/drivers/media/platform/vivid/Makefile @@ -2,5 +2,5 @@ vivid-objs := vivid-core.o vivid-ctrls.o vivid-vid-common.o vivid-vbi-gen.o \ vivid-vid-cap.o vivid-vid-out.o vivid-kthread-cap.o vivid-kthread-out.o \ vivid-radio-rx.o vivid-radio-tx.o vivid-radio-common.o \ vivid-rds-gen.o vivid-sdr-cap.o vivid-vbi-cap.o vivid-vbi-out.o \ - vivid-osd.o vivid-tpg.o vivid-tpg-colors.o + vivid-osd.o vivid-tpg.o vivid-tpg-colors.o vivid-sin.o obj-$(CONFIG_VIDEO_VIVID) += vivid.o diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c index 4af55f1..1f8b328 100644 --- a/drivers/media/platform/vivid/vivid-sdr-cap.c +++ b/drivers/media/platform/vivid/vivid-sdr-cap.c @@ -31,6 +31,7 @@ #include "vivid-core.h" #include "vivid-ctrls.h" #include "vivid-sdr-cap.h" +#include "vivid-sin.h" static const struct v4l2_frequency_band bands_adc[] = { { @@ -423,40 +424,17 @@ int vidioc_g_fmt_sdr_cap(struct file *file, void *fh, struct v4l2_format *f) return 0; } -#define FIXP_FRAC (1 << 15) -#define FIXP_PI ((int)(FIXP_FRAC * 3.141592653589)) - -/* cos() from cx88 driver: cx88-dsp.c */ -static s32 fixp_cos(unsigned int x) -{ - u32 t2, t4, t6, t8; - u16 period = x / FIXP_PI; - - if (period % 2) - return -fixp_cos(x - FIXP_PI); - x = x % FIXP_PI; - if (x > FIXP_PI/2) - return -fixp_cos(FIXP_PI/2 - (x % (FIXP_PI/2))); - /* Now x is between 0 and FIXP_PI/2. - * To calculate cos(x) we use it's Taylor polinom. */ - t2 = x*x/FIXP_FRAC/2; - t4 = t2*x/FIXP_FRAC*x/FIXP_FRAC/3/4; - t6 = t4*x/FIXP_FRAC*x/FIXP_FRAC/5/6; - t8 = t6*x/FIXP_FRAC*x/FIXP_FRAC/7/8; - return FIXP_FRAC-t2+t4-t6+t8; -} - -static inline s32 fixp_sin(unsigned int x) -{ - return -fixp_cos(x + (FIXP_PI / 2)); -} - void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) { u8 *vbuf = vb2_plane_vaddr(&buf->vb, 0); unsigned long i; unsigned long plane_size = vb2_plane_size(&buf->vb, 0); - int fixp_src_phase_step, fixp_i, fixp_q; + int fixp_i, fixp_q; + + u32 adc_freq; + u32 sig_freq; + s32 src_phase_inc; + s32 mod_phase_inc; /* * TODO: Generated beep tone goes very crackly when sample rate is @@ -466,34 +444,41 @@ void vivid_sdr_cap_process(struct vivid_dev *dev, struct vivid_buffer *buf) /* calculate phase step */ #define BEEP_FREQ 1000 /* 1kHz beep */ - fixp_src_phase_step = DIV_ROUND_CLOSEST(2 * FIXP_PI * BEEP_FREQ, - dev->sdr_adc_freq); + + adc_freq = dev->sdr_adc_freq; /* samples per sec*/ + sig_freq = BEEP_FREQ; /* cycles per sec */ + src_phase_inc = phase_per_sample(sig_freq, adc_freq); for (i = 0; i < plane_size; i += 2) { - dev->sdr_fixp_mod_phase += fixp_cos(dev->sdr_fixp_src_phase); - dev->sdr_fixp_src_phase += fixp_src_phase_step; - /* - * Transfer phases to [0 / 2xPI] in order to avoid variable - * overflow and make it suitable for cosine implementation - * used, which does not support negative angles. - */ - while (dev->sdr_fixp_mod_phase < (0 * FIXP_PI)) - dev->sdr_fixp_mod_phase += (2 * FIXP_PI); - while (dev->sdr_fixp_mod_phase > (2 * FIXP_PI)) - dev->sdr_fixp_mod_phase -= (2 * FIXP_PI); + mod_phase_inc = calc_cos(dev->sdr_fixp_src_phase); + dev->sdr_fixp_src_phase += src_phase_inc; + + while (dev->sdr_fixp_src_phase >= ((44 << FIX_PT_PREC)/7)) + dev->sdr_fixp_src_phase -= ((44 << FIX_PT_PREC)/7); + + mod_phase_inc <<= FIX_PT_PREC; + mod_phase_inc /= 1275; + + dev->sdr_fixp_mod_phase += mod_phase_inc; + + while (dev->sdr_fixp_mod_phase < 0) + dev->sdr_fixp_mod_phase += ((44 << FIX_PT_PREC) / 7); - while (dev->sdr_fixp_src_phase > (2 * FIXP_PI)) - dev->sdr_fixp_src_phase -= (2 * FIXP_PI); + while (dev->sdr_fixp_mod_phase >= ((44 << FIX_PT_PREC) / 7)) + dev->sdr_fixp_mod_phase -= ((44 << FIX_PT_PREC) / 7); - fixp_i = fixp_cos(dev->sdr_fixp_mod_phase); - fixp_q = fixp_sin(dev->sdr_fixp_mod_phase); + fixp_i = calc_sin(dev->sdr_fixp_mod_phase); + fixp_q = calc_cos(dev->sdr_fixp_mod_phase); /* convert 'fixp float' to u8 */ - /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] */ - fixp_i = fixp_i * 1275 + FIXP_FRAC * 1275; - fixp_q = fixp_q * 1275 + FIXP_FRAC * 1275; - *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, FIXP_FRAC * 10); - *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, FIXP_FRAC * 10); + /* u8 = X * 127.5f + 127.5f; where X is float [-1.0 / +1.0] + The values stored in sin look table are pre-multipied with 1275. + So, only do addition */ + + fixp_i += 1275; + fixp_q += 1275; + *vbuf++ = DIV_ROUND_CLOSEST(fixp_i, 10); + *vbuf++ = DIV_ROUND_CLOSEST(fixp_q, 10); } } diff --git a/drivers/media/platform/vivid/vivid-sin.c b/drivers/media/platform/vivid/vivid-sin.c new file mode 100644 index 0000000..e3d6149 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-sin.c @@ -0,0 +1,184 @@ +/* + * vivid-sin.c - software defined radio support functions. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights + * reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#include <linux/errno.h> +#include <linux/kernel.h> + +#include "vivid-sin.h" + +#define SIN_TAB_SIZE 256 + + /*TODO- Reduce the size of the table */ +/* Since sinewave is symmetric, it can be represented using only quarter + of the samples compared to the number of samples used below */ + +static s32 sin[257] = { + 0, 31, 63, 94, 125, 156, 187, 218, + 249, 279, 310, 340, 370, 400, 430, 459, + 488, 517, 545, 573, 601, 628, 655, 682, + 708, 734, 760, 784, 809, 833, 856, 879, + 902, 923, 945, 965, 986, 1005, 1024, 1042, + 1060, 1077, 1094, 1109, 1124, 1139, 1153, 1166, + 1178, 1190, 1200, 1211, 1220, 1229, 1237, 1244, + 1251, 1256, 1261, 1265, 1269, 1272, 1273, 1275, + 1275, 1275, 1273, 1272, 1269, 1265, 1261, 1256, + 1251, 1244, 1237, 1229, 1220, 1211, 1200, 1190, + 1178, 1166, 1153, 1139, 1124, 1109, 1094, 1077, + 1060, 1042, 1024, 1005, 986, 965, 945, 923, + 902, 879, 856, 833, 809, 784, 760, 734, + 708, 682, 655, 628, 601, 573, 545, 517, + 488, 459, 430, 400, 370, 340, 310, 279, + 249, 218, 187, 156, 125, 94, 63, 31, + 0, -31, -63, -94, -125, 156, -187, -218, + -249, -279, -310, -340, -370, -400, -430, -459, + -488, -517, -545, -573, -601, -628, -655, -682, + -708, -734, -760, -784, -809, -833, -856, -879, + -902, -923, -945, -965, -986, -1005, -1024, -1042, + -1060, -1077, -1094, -1109, -1124, -1139, -1153, -1166, + -1178, -1190, -1200, -1211, -1220, -1229, -1237, -1244, + -1251, -1256, -1261, -1265, -1269, -1272, -1273, -1275, + -1275, -1275, -1273, -1272, -1269, -1265, -1261, -1256, + -1251, -1244, -1237, -1229, -1220, -1211, -1200, -1190, + -1178, -1166, -1153, -1139, -1124, -1109, -1094, -1077, + -1060, -1042, -1024, -1005, -986, -965, -945, -923, + -902, -879, -856, -833, -809, -784, -760, -734, + -708, -682, -655, -628, -601, -573, -545, -517, + -488, -459, -430, -400, -370, -340, -310, -279, + -249, -218, -187, -156, -125, -94, -63, -31, + 0 + }; + +/* + * Calculation of sine is implemented using a look up table for range of + * phase values from 0 to 2*pi. Look table contains finite entries, say N. + * + * Since sinusoid are periodic with period 2*pi, look table stores entries + * for phase values from 0 to 2*pi. + * + * The interval [0,2*pi] is divided into N equal intervals, each representing + * a phase increment of (2*pi/N) + * + * The index 'n' in look up table stores sine value for phase (2*pi*n/N) as - + * sin_tab[N] = {sin(0), sin(1*(2*pi/N)),sin(2*(2*pi/N)), ..., sin(N*(2*pi/N))} + * + |---------|---------|---------|---- . . . .|---------| . . . . |---------| + 0 (2*pi/N) (2*2*pi/N) (3*2*pi/N) (n*2*pi/N) 2*pi + * + * Generation of sine waveform with different frequencies - + * + * Consider a sine tone with frequency 'f', so, + * num_cycles_per_sec = f + * Let sampling frequency be 'Fs' so, + * num_samples_per_sec = Fs + * So, num_samples_per_cycle = Fs/f + * Let Nc = Fs/f + * + * That is, number of samples during one interval of 0 tp 2*pi = Nc, each + * sample represents a phase increment of (2*pi/Nc = 2*pi*f/Fs). + * + * So, for "k" th sample the phase, phi = k*(2*pi/Nc) + * + * The sine value at phase increments of (2*pi / Nc) is calculated by + * interpolating two adjecent samples from sine look table + * + * As an example, sine value for phase (phi) is calculated below + * + * 1. Find the interval [(n*2*pi/N), ((n+1)*2*pi/N)] to which phi belongs + + * 0 (2*pi/N) (n*2*pi/N) ((n+1)*2*pi/N) 2*pi + * |---------| . . . . . |---------|---------| . . . . . |---------| + * ^ + * d0-- > | < --d1 + * | + * phi = k*(2*pi/Nc) + * + * For phase (phi) the index n in sine table is given by (phi)/(2*pi/N) + * n = integer part of ( phi / (2*pi / N) ) + * + * 2. Find distance d0 and d1 using fractional arithmatic. + * d0 = phi - n*(2*pi / N), + * d1 = 2*pi / N - d0 + * + * 3. The calculations of fractions are done using fixed point implementation + * + * 4. To improve the precision of fixed point implementations, divisions + * in different calculations are delayed till last operations. Say, + * d0 = phi - n*(2*pi / N) + * d0 = phi - n * (2 * (22 / 7) / N) , substitute pi = 22 / 7 + * d0 = phi - (n * 44 * N) / 7 + */ +s32 calc_sin(u32 phase) +{ + u32 index; + u32 d0; + u32 d1; + s32 result; + u64 temp0; + u64 temp1; + + temp0 = phase * SIN_TAB_SIZE; + index = (temp0 * 7) / (44 << FIX_PT_PREC); + + temp0 = (temp0 * 7) / 44; + temp1 = index << FIX_PT_PREC; + + d1 = temp0 - temp1; + d0 = (1 << FIX_PT_PREC) - d1; + + result = (d0 * sin[index % 256] + d1 * sin[(index+1)%256]); + + return result >> FIX_PT_PREC; +} + +s32 calc_cos(u32 phase) +{ + u32 index; + u32 d0; + u32 d1; + s32 result; + u64 temp0; + u64 temp1; + + temp0 = phase * SIN_TAB_SIZE; + index = (temp0 * 7) / (44 << FIX_PT_PREC); + + temp0 = (temp0 * 7) / 44; + temp1 = index << FIX_PT_PREC; + + d1 = temp0 - temp1; + d0 = (1 << FIX_PT_PREC) - d1; + + index += 64; + result = (d0 * sin[index % 256] + d1 * sin[(index+1)%256]); + + return result >> FIX_PT_PREC; +} + +u32 phase_per_sample(u32 signal_freq, u32 sampling_freq) +{ + /* phase increment or decrement with each sample is given by + * (2 x Pi x signal frequency)/sampling frequency + * To get a better accuracy with fixed point implementation we use + * Pi = 22/7 + * */ + u64 temp = 44 * ((u64)signal_freq << FIX_PT_PREC); + + return temp / (7*sampling_freq); +} diff --git a/drivers/media/platform/vivid/vivid-sin.h b/drivers/media/platform/vivid/vivid-sin.h new file mode 100644 index 0000000..6c8bab2 --- /dev/null +++ b/drivers/media/platform/vivid/vivid-sin.h @@ -0,0 +1,31 @@ +/* + * vivid-sin.h - support functions used to generate (co)sine waveforms for + * software defined radio. + * + * Copyright 2014 Cisco Systems, Inc. and/or its affiliates. All rights + * reserved. + * + * This program is free software; you may redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS + * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN + * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef _VIVID_SIN_H_ +#define _VIVID_SIN_H_ + +#define FIX_PT_PREC 16 + +s32 calc_sin(u32 phase); +s32 calc_cos(u32 phase); +u32 phase_per_sample(u32 signal_freq, u32 sampling_freq); + +#endif
Replaced Taylor series calculation for (co)sine with a look up table (LUT) for sine values. Also reworked fixed point implementation to reduce rounding errors. Cc: Hans Verkuil <hans.verkuil@cisco.com> Cc: Antti Palosaari <crope@iki.fi> Cc: Mauro Carvalho Chehab <mchehab@osg.samsung.com> Signed-off-by: Prashant Laddha <prladdha@cisco.com> --- drivers/media/platform/vivid/Makefile | 2 +- drivers/media/platform/vivid/vivid-sdr-cap.c | 87 ++++++------- drivers/media/platform/vivid/vivid-sin.c | 184 +++++++++++++++++++++++++++ drivers/media/platform/vivid/vivid-sin.h | 31 +++++ 4 files changed, 252 insertions(+), 52 deletions(-) create mode 100644 drivers/media/platform/vivid/vivid-sin.c create mode 100644 drivers/media/platform/vivid/vivid-sin.h