diff --git a/csdr.c b/csdr.c
index 18472d6..bd74cf2 100644
--- a/csdr.c
+++ b/csdr.c
@@ -486,6 +486,55 @@ int main(int argc, char *argv[])
return 0;
}
+ if(!strcmp(argv[1],"shift_addfast_cc"))
+ {
+ bigbufs=1;
+
+ float starting_phase=0;
+ float rate;
+
+ int fd;
+ if(fd=init_fifo(argc,argv))
+ {
+ while(!read_fifo_ctl(fd,"%g\n",&rate)) usleep(10000);
+ }
+ else
+ {
+ if(argc<=2) return badsyntax("need required parameter (rate)");
+ sscanf(argv[2],"%g",&rate);
+ }
+
+ if(!sendbufsize(initialize_buffers())) return -2;
+ for(;;)
+ {
+ shift_addfast_data_t data=shift_addfast_init(rate);
+ fprintf(stderr,"shift_addfast_cc: reinitialized to %g\n",rate);
+ int remain, current_size;
+ float* ibufptr;
+ float* obufptr;
+ for(;;)
+ {
+ FEOF_CHECK;
+ if(!FREAD_C) break;
+ remain=the_bufsize;
+ ibufptr=input_buffer;
+ obufptr=output_buffer;
+ while(remain)
+ {
+ current_size=(remain>1024)?1024:remain;
+ starting_phase=shift_addfast_cc((complexf*)ibufptr, (complexf*)obufptr, current_size, &data, starting_phase);
+ ibufptr+=current_size*2;
+ obufptr+=current_size*2;
+ remain-=current_size;
+ }
+ FWRITE_C;
+ if(read_fifo_ctl(fd,"%g\n",&rate)) break;
+ TRY_YIELD;
+ }
+ }
+ return 0;
+ }
+
#ifdef LIBCSDR_GPL
if(!strcmp(argv[1],"decimating_shift_addition_cc"))
{
diff --git a/grc_tests/test_shift_remote.grc b/grc_tests/test_shift_remote.grc
new file mode 100644
index 0000000..516635f
--- /dev/null
+++ b/grc_tests/test_shift_remote.grc
@@ -0,0 +1,912 @@
+
+
+
+ Thu Jan 15 18:51:48 2015
+
+ options
+
+ author
+
+
+
+ window_size
+ 1280, 1024
+
+
+ category
+ Custom
+
+
+ comment
+
+
+
+ description
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (10, 10)
+
+
+ _rotation
+ 0
+
+
+ generate_options
+ wx_gui
+
+
+ id
+ top_block
+
+
+ max_nouts
+ 0
+
+
+ realtime_scheduling
+
+
+
+ run_options
+ prompt
+
+
+ run
+ True
+
+
+ thread_safe_setters
+
+
+
+ title
+
+
+
+
+ variable
+
+ comment
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (8, 195)
+
+
+ _rotation
+ 0
+
+
+ id
+ rate
+
+
+ value
+ -0.1
+
+
+
+ variable
+
+ comment
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (176, 11)
+
+
+ _rotation
+ 0
+
+
+ id
+ samp_rate
+
+
+ value
+ 250e3
+
+
+
+ analog_sig_source_x
+
+ amp
+ 1
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ freq
+ 20000
+
+
+ _coordinate
+ (8, 75)
+
+
+ _rotation
+ 0
+
+
+ id
+ analog_sig_source_x_0
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ offset
+ 0
+
+
+ type
+ complex
+
+
+ samp_rate
+ samp_rate
+
+
+ waveform
+ analog.GR_CONST_WAVE
+
+
+
+ blocks_throttle
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (224, 107)
+
+
+ _rotation
+ 0
+
+
+ id
+ blocks_throttle_0
+
+
+ ignoretag
+ True
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ samples_per_second
+ samp_rate
+
+
+ type
+ complex
+
+
+ vlen
+ 1
+
+
+
+ ha5kfu_execproc_xx
+
+ alias
+
+
+
+ commandline
+ "csdr shift_addition_cc %g"%rate
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (824, 315)
+
+
+ _rotation
+ 0
+
+
+ id
+ ha5kfu_execproc_xx_0_0
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ type
+ cc
+
+
+
+ ha5kfu_execproc_xx
+
+ alias
+
+
+
+ commandline
+ ncat -vv raspberrypi.local 5321
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (536, 443)
+
+
+ _rotation
+ 0
+
+
+ id
+ ha5kfu_execproc_xx_0_0_0_1
+
+
+ maxoutbuf
+ 0
+
+
+ minoutbuf
+ 0
+
+
+ type
+ cc
+
+
+
+ notebook
+
+ alias
+
+
+
+ comment
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (272, 11)
+
+
+ _rotation
+ 0
+
+
+ grid_pos
+
+
+
+ id
+ nb0
+
+
+ labels
+ ['original', 'shift_addition_cc','shift_addfast_cc',]
+
+
+ notebook
+
+
+
+ style
+ wx.NB_TOP
+
+
+
+ wxgui_fftsink2
+
+ avg_alpha
+ 0
+
+
+ average
+ False
+
+
+ baseband_freq
+ 0
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ fft_size
+ 1024
+
+
+ freqvar
+ None
+
+
+ _coordinate
+ (848, 27)
+
+
+ _rotation
+ 0
+
+
+ grid_pos
+
+
+
+ id
+ wxgui_fftsink2_0_0
+
+
+ notebook
+ nb0,0
+
+
+ peak_hold
+ False
+
+
+ ref_level
+ 0
+
+
+ ref_scale
+ 2.0
+
+
+ fft_rate
+ 15
+
+
+ samp_rate
+ samp_rate
+
+
+ title
+ FFT Plot
+
+
+ type
+ complex
+
+
+ win_size
+
+
+
+ win
+ None
+
+
+ y_divs
+ 10
+
+
+ y_per_div
+ 10
+
+
+
+ wxgui_fftsink2
+
+ avg_alpha
+ 0
+
+
+ average
+ False
+
+
+ baseband_freq
+ 0
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ fft_size
+ 1024
+
+
+ freqvar
+ None
+
+
+ _coordinate
+ (1112, 339)
+
+
+ _rotation
+ 0
+
+
+ grid_pos
+
+
+
+ id
+ wxgui_fftsink2_0_1
+
+
+ notebook
+ nb0,1
+
+
+ peak_hold
+ False
+
+
+ ref_level
+ 0
+
+
+ ref_scale
+ 2.0
+
+
+ fft_rate
+ 15
+
+
+ samp_rate
+ samp_rate
+
+
+ title
+ FFT Plot
+
+
+ type
+ complex
+
+
+ win_size
+
+
+
+ win
+ None
+
+
+ y_divs
+ 10
+
+
+ y_per_div
+ 10
+
+
+
+ wxgui_fftsink2
+
+ avg_alpha
+ 0
+
+
+ average
+ False
+
+
+ baseband_freq
+ 0
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ fft_size
+ 1024
+
+
+ freqvar
+ None
+
+
+ _coordinate
+ (808, 387)
+
+
+ _rotation
+ 0
+
+
+ grid_pos
+
+
+
+ id
+ wxgui_fftsink2_0_1_1
+
+
+ notebook
+ nb0,2
+
+
+ peak_hold
+ False
+
+
+ ref_level
+ 0
+
+
+ ref_scale
+ 2.0
+
+
+ fft_rate
+ 15
+
+
+ samp_rate
+ samp_rate
+
+
+ title
+ FFT Plot
+
+
+ type
+ complex
+
+
+ win_size
+
+
+
+ win
+ None
+
+
+ y_divs
+ 10
+
+
+ y_per_div
+ 10
+
+
+
+ wxgui_scopesink2
+
+ ac_couple
+ False
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (1112, 555)
+
+
+ _rotation
+ 0
+
+
+ grid_pos
+
+
+
+ id
+ wxgui_scopesink2_0_0
+
+
+ notebook
+ nb0,1
+
+
+ num_inputs
+ 1
+
+
+ samp_rate
+ samp_rate
+
+
+ t_scale
+ 0
+
+
+ title
+ Scope Plot
+
+
+ trig_mode
+ wxgui.TRIG_MODE_NORM
+
+
+ type
+ complex
+
+
+ v_offset
+ 0
+
+
+ v_scale
+ 0
+
+
+ win_size
+
+
+
+ xy_mode
+ False
+
+
+ y_axis_label
+ Counts
+
+
+
+ wxgui_scopesink2
+
+ ac_couple
+ False
+
+
+ alias
+
+
+
+ comment
+
+
+
+ affinity
+
+
+
+ _enabled
+ True
+
+
+ _coordinate
+ (808, 611)
+
+
+ _rotation
+ 0
+
+
+ grid_pos
+
+
+
+ id
+ wxgui_scopesink2_0_0_1
+
+
+ notebook
+ nb0,2
+
+
+ num_inputs
+ 1
+
+
+ samp_rate
+ samp_rate
+
+
+ t_scale
+ 0
+
+
+ title
+ Scope Plot
+
+
+ trig_mode
+ wxgui.TRIG_MODE_NORM
+
+
+ type
+ complex
+
+
+ v_offset
+ 0
+
+
+ v_scale
+ 0
+
+
+ win_size
+
+
+
+ xy_mode
+ False
+
+
+ y_axis_label
+ Counts
+
+
+
+ analog_sig_source_x_0
+ blocks_throttle_0
+ 0
+ 0
+
+
+ blocks_throttle_0
+ ha5kfu_execproc_xx_0_0
+ 0
+ 0
+
+
+ blocks_throttle_0
+ ha5kfu_execproc_xx_0_0_0_1
+ 0
+ 0
+
+
+ blocks_throttle_0
+ wxgui_fftsink2_0_0
+ 0
+ 0
+
+
+ ha5kfu_execproc_xx_0_0
+ wxgui_fftsink2_0_1
+ 0
+ 0
+
+
+ ha5kfu_execproc_xx_0_0
+ wxgui_scopesink2_0_0
+ 0
+ 0
+
+
+ ha5kfu_execproc_xx_0_0_0_1
+ wxgui_fftsink2_0_1_1
+ 0
+ 0
+
+
+ ha5kfu_execproc_xx_0_0_0_1
+ wxgui_scopesink2_0_0_1
+ 0
+ 0
+
+
diff --git a/grc_tests/test_shift_remote.sh b/grc_tests/test_shift_remote.sh
new file mode 100755
index 0000000..65c7192
--- /dev/null
+++ b/grc_tests/test_shift_remote.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+# Run this script on a Raspberry Pi 2, while running test_shift_remote.grc on your PC.
+# It allows you to debug the NEON-accelerated version of specific DSP algorithms on the target hardware.
+TEMPSCRIPT="/tmp/test_shift_remote_exec.sh"
+echo '#!/bin/sh\ncsdr shift_addfast_cc -0.1' > $TEMPSCRIPT
+cat $TEMPSCRIPT
+chmod +x $TEMPSCRIPT
+ncat -vvl 5321 -e $TEMPSCRIPT
+rm $TEMPSCRIPT
diff --git a/libcsdr.c b/libcsdr.c
index e6b5b31..09fe664 100644
--- a/libcsdr.c
+++ b/libcsdr.c
@@ -263,6 +263,45 @@ float shift_table_cc(complexf* input, complexf* output, int input_size, float ra
return phase;
}
+
+
+shift_addfast_data_t shift_addfast_init(float rate)
+{
+ shift_addfast_data_t output;
+ float phase_increment=2*rate*PI;
+ for(int i=0;i<4;i++)
+ {
+ output.dsin[i]=sin(phase_increment*(i+1));
+ output.dcos[i]=cos(phase_increment*(i+1));
+ }
+ return output;
+}
+
+float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase)
+{
+ //input_size should be multiple of 4
+ float phase=starting_phase;
+ float cos_start=cos(starting_phase);
+ float sin_start=sin(starting_phase);
+ float cos_vals[4], sin_vals[4];
+ for(int i=0;idcos[i] - sin_start * d->dsin[i];
+ sin_vals[i] = sin_start * d->dcos[i] + cos_start * d->dsin[i];
+ }
+ for(int j=0;j<4;j++)
+ {
+ iof(output,4*i+j)=cos_vals[j]*iof(input,4*i+j)-sin_vals[j]*qof(input,4*i+j);
+ qof(output,4*i+j)=sin_vals[j]*iof(input,4*i+j)+cos_vals[j]*qof(input,4*i+j);
+ }
+ cos_start = cos_vals[3];
+ sin_start = sin_vals[3];
+ }
+ return phase;
+}
+
#ifdef NEON_OPTS
#pragma message "We have a faster fir_decimate_cc now."
diff --git a/libcsdr.h b/libcsdr.h
index ca4a311..f3e154e 100644
--- a/libcsdr.h
+++ b/libcsdr.h
@@ -156,6 +156,15 @@ void shift_table_deinit(shift_table_data_t table_data);
shift_table_data_t shift_table_init(int table_size);
float shift_table_cc(complexf* input, complexf* output, int input_size, float rate, shift_table_data_t table_data, float starting_phase);
+typedef struct shift_addfast_data_s
+{
+ float dsin[4];
+ float dcos[4];
+
+} shift_addfast_data_t;
+shift_addfast_data_t shift_addfast_init(float rate);
+float shift_addfast_cc(complexf *input, complexf* output, int input_size, shift_addfast_data_t* d, float starting_phase);
+
int log2n(int x);
int next_pow2(int x);
diff --git a/make_test200 b/make_test200
new file mode 100755
index 0000000..7e5cc05
--- /dev/null
+++ b/make_test200
@@ -0,0 +1,2 @@
+#!/bin/bash
+gcc test200.c --std=gnu99 -o test200 -DUSE_FFTW -DLIBCSDR_GPL -lcsdr
diff --git a/test200.c b/test200.c
new file mode 100644
index 0000000..c2166c9
--- /dev/null
+++ b/test200.c
@@ -0,0 +1,84 @@
+/*
+This software is part of libcsdr, a set of simple DSP routines for
+Software Defined Radio.
+
+Copyright (c) 2014-2015, Andras Retzler
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the copyright holder nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL ANDRAS RETZLER BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "libcsdr.h"
+#include "libcsdr_gpl.h"
+
+#define T_BUFSIZE (1024*1024/4)
+#define T_N (200)
+
+int main()
+{
+ fprintf(stderr,"Getting a %d of random samples...\n", T_BUFSIZE);
+ int urand_fp = open("/dev/urandom",O_RDWR);
+ unsigned char* buf_u8 = (unsigned char*)malloc(sizeof(unsigned char)*T_BUFSIZE*2);
+ complexf* buf_c = (complexf*)malloc(sizeof(complexf)*T_BUFSIZE);
+ complexf* outbuf_c = (complexf*)malloc(sizeof(complexf)*T_BUFSIZE);
+ read(urand_fp, buf_u8, T_BUFSIZE);
+ close(urand_fp);
+
+ for(int i=0;i