diff mbox

[1/6] Use LUT based implementation for (co)sine functions

Message ID 1418635162-8814-2-git-send-email-prladdha@cisco.com (mailing list archive)
State New, archived
Headers show

Commit Message

Prashant Laddha Dec. 15, 2014, 9:19 a.m. UTC
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

Comments

Prashant Laddha Dec. 15, 2014, 9:24 a.m. UTC | #1
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
Mauro Carvalho Chehab Dec. 15, 2014, 1:13 p.m. UTC | #2
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
Antti Palosaari Dec. 15, 2014, 1:30 p.m. UTC | #3
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
Prashant Laddha Dec. 16, 2014, 6:41 a.m. UTC | #4
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
Mauro Carvalho Chehab Dec. 16, 2014, 10:45 a.m. UTC | #5
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
Mauro Carvalho Chehab Dec. 16, 2014, 11:40 a.m. UTC | #6
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 mbox

Patch

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