From 0c03bcd68f94ceb96de7c9fd17410f08d3acff18 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Wed, 16 Apr 2014 16:44:11 +0100 Subject: [PATCH 1/2] Adding arbitrary resampler with tests and benchmark --- lte/include/lte/resampling/resample_arb.h | 49 ++++++++ lte/lib/resampling/src/resample_arb.c | 114 +++++++++++++++++++ lte/lib/resampling/test/CMakeLists.txt | 35 ++++++ lte/lib/resampling/test/resample_arb_bench.c | 38 +++++++ lte/lib/resampling/test/resample_arb_test.c | 63 ++++++++++ 5 files changed, 299 insertions(+) create mode 100644 lte/include/lte/resampling/resample_arb.h create mode 100644 lte/lib/resampling/src/resample_arb.c create mode 100644 lte/lib/resampling/test/CMakeLists.txt create mode 100644 lte/lib/resampling/test/resample_arb_bench.c create mode 100644 lte/lib/resampling/test/resample_arb_test.c diff --git a/lte/include/lte/resampling/resample_arb.h b/lte/include/lte/resampling/resample_arb.h new file mode 100644 index 000000000..122e52a6d --- /dev/null +++ b/lte/include/lte/resampling/resample_arb.h @@ -0,0 +1,49 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#ifndef RESAMPLE_ARB_ +#define RESAMPLE_ARB_ + +#include +#include + +typedef _Complex float cf_t; + +#define RESAMPLE_ARB_N 32 // Polyphase filter rows +#define RESAMPLE_ARB_M 8 // Polyphase filter columns + +typedef struct { + float rate; // Resample rate + float step; // Step increment through filter + float acc; // Index into filter + cf_t reg[RESAMPLE_ARB_M]; // Our window of samples +}resample_arb_t; + +void resample_arb_init(resample_arb_t *q, float rate); +int resample_arb_compute(resample_arb_t *q, cf_t *input, cf_t *output, int n_in); + +#endif //RESAMPLE_ARB_ diff --git a/lte/lib/resampling/src/resample_arb.c b/lte/lib/resampling/src/resample_arb.c new file mode 100644 index 000000000..8ba00995a --- /dev/null +++ b/lte/lib/resampling/src/resample_arb.c @@ -0,0 +1,114 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2014 The libLTE Developers. See the + * COPYRIGHT file at the top-level directory of this distribution. + * + * \section LICENSE + * + * This file is part of the libLTE library. + * + * libLTE is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * libLTE is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * A copy of the GNU Lesser General Public License can be found in + * the LICENSE file in the top-level directory of this distribution + * and at http://www.gnu.org/licenses/. + * + */ + +#include +#include +#include "lte/resampling/resample_arb.h" +#include "lte/utils/debug.h" + +float polyfilt[RESAMPLE_ARB_N][RESAMPLE_ARB_M] = +{{0,0.002400347599485495,-0.006922416132556366,0.0179104136912176,0.99453086623794,-0.008521087756729117,0.0008598969867484128,0.0004992625165376107}, +{-0.001903604727400391,0.004479591950094871,-0.01525319260830623,0.04647449496926549,0.9910477342662829,-0.03275243420114668,0.008048813755373533,-0.001216900416836847}, +{-0.001750442300940216,0.006728826416921727,-0.02407540632178267,0.07708575473589654,0.9841056525667189,-0.05473739187922162,0.01460652754040275,-0.002745266140572769}, +{-0.001807302702047332,0.009130494591071001,-0.03332524241797466,0.1096377743266821,0.9737536341125557,-0.07444712408657775,0.0205085154280773,-0.004077596041064956}, +{-0.002005048395707184,0.01166717081713966,-0.04292591596219218,0.1440068251440274,0.9600641782991848,-0.09187282739868929,0.02573649090563353,-0.005218582609802016}, +{-0.002303606593778858,0.01431549924598744,-0.05279365431190471,0.1800496557331084,0.9431333663677619,-0.107022659158021,0.03028295984887362,-0.006178495199082676}, +{-0.002673824939871474,0.01705308556587308,-0.06283262272105428,0.2176066284621515,0.9230793648715676,-0.1199244901666642,0.03414559686566755,-0.006951034565279722}, +{-0.003099294850834212,0.01985022208215894,-0.07294100481214681,0.2564996326404178,0.9000412628278351,-0.1306207218667012,0.03733448898243594,-0.007554128492547957}, +{-0.003564415127592977,0.02267702927238637,-0.08300660359189582,0.2965368855416621,0.874178327911914,-0.1391710078036285,0.03986356581130199,-0.007992692892036229}, +{-0.004060222849803048,0.02549633298710617,-0.09291211362877161,0.3375102453232687,0.8456688916962831,-0.1456479420005528,0.04175429631970297,-0.00827816851803391}, +{-0.004574770330592958,0.02827133859849648,-0.1025308044303699,0.379200979038518,0.8147072909915275,-0.1501397816831265,0.04303284689167361,-0.008423951215857236}, +{-0.005100453570725489,0.0309593063669097,-0.1117325201826136,0.4213772298764557,0.7815036335229155,-0.1527444636485677,0.0437349357738538,-0.008441129184587313}, +{-0.005625340687997995,0.03351877124912608,-0.1203802123857154,0.463798444519773,0.7462810500374923,-0.1535722712206338,0.04389261707032224,-0.008345136869130621}, +{-0.006140888413286479,0.03590276234084221,-0.1283350405000867,0.5062161107254219,0.7092744343987509,-0.152741400055636,0.04355110899623683,-0.008147838953503964}, +{-0.006634012711933725,0.03806645580467819,-0.1354549138065051,0.5483763739419955,0.6707272107491931,-0.1503798528838644,0.0427502160096194,-0.007865132034489236}, +{-0.007094909626785393,0.03996043743797257,-0.1415969539549883,0.5900207719663111,0.6308907308946271,-0.1466186670140106,0.04153829696698895,-0.007508971112586246}, +{-0.007508971112586246,0.04153829696698895,-0.1466186670140106,0.6308907308946271,0.5900207719663111,-0.1415969539549883,0.03996043743797257,-0.007094909626785393}, +{-0.007865132034489236,0.0427502160096194,-0.1503798528838644,0.6707272107491931,0.5483763739419955,-0.1354549138065051,0.03806645580467819,-0.006634012711933725}, +{-0.008147838953503964,0.04355110899623683,-0.152741400055636,0.7092744343987509,0.5062161107254219,-0.1283350405000867,0.03590276234084221,-0.006140888413286479}, +{-0.008345136869130621,0.04389261707032224,-0.1535722712206338,0.7462810500374923,0.463798444519773,-0.1203802123857154,0.03351877124912608,-0.005625340687997995}, +{-0.008441129184587313,0.0437349357738538,-0.1527444636485677,0.7815036335229155,0.4213772298764557,-0.1117325201826136,0.0309593063669097,-0.005100453570725489}, +{-0.008423951215857236,0.04303284689167361,-0.1501397816831265,0.8147072909915275,0.379200979038518,-0.1025308044303699,0.02827133859849648,-0.004574770330592958}, +{-0.00827816851803391,0.04175429631970297,-0.1456479420005528,0.8456688916962831,0.3375102453232687,-0.09291211362877161,0.02549633298710617,-0.004060222849803048}, +{-0.007992692892036229,0.03986356581130199,-0.1391710078036285,0.874178327911914,0.2965368855416621,-0.08300660359189582,0.02267702927238637,-0.003564415127592977}, +{-0.007554128492547957,0.03733448898243594,-0.1306207218667012,0.9000412628278351,0.2564996326404178,-0.07294100481214681,0.01985022208215894,-0.003099294850834212}, +{-0.006951034565279722,0.03414559686566755,-0.1199244901666642,0.9230793648715676,0.2176066284621515,-0.06283262272105428,0.01705308556587308,-0.002673824939871474}, +{-0.006178495199082676,0.03028295984887362,-0.107022659158021,0.9431333663677619,0.1800496557331084,-0.05279365431190471,0.01431549924598744,-0.002303606593778858}, +{-0.005218582609802016,0.02573649090563353,-0.09187282739868929,0.9600641782991848,0.1440068251440274,-0.04292591596219218,0.01166717081713966,-0.002005048395707184}, +{-0.004077596041064956,0.0205085154280773,-0.07444712408657775,0.9737536341125557,0.1096377743266821,-0.03332524241797466,0.009130494591071001,-0.001807302702047332}, +{-0.002745266140572769,0.01460652754040275,-0.05473739187922162,0.9841056525667189,0.07708575473589654,-0.02407540632178267,0.006728826416921727,-0.001750442300940216}, +{-0.001216900416836847,0.008048813755373533,-0.03275243420114668,0.9910477342662829,0.04647449496926549,-0.01525319260830623,0.004479591950094871,-0.001903604727400391}, +{0.0004992625165376107,0.0008598969867484128,-0.008521087756729117,0.99453086623794,0.0179104136912176,-0.006922416132556366,0.002400347599485495,0}}; + + +// TODO: use lte/utils/vector.h and Volk +cf_t dot_prod(cf_t* x, float *y, int len) +{ + cf_t res = 0+0*I; + for(int i=0;ireg[1], &q->reg[0], (RESAMPLE_ARB_M-1)*sizeof(cf_t)); + q->reg[0] = x; +} + +// Initialize our struct +void resample_arb_init(resample_arb_t *q, float rate){ + memset(q->reg, 0, RESAMPLE_ARB_M*sizeof(cf_t)); + q->acc = 0.0; + q->rate = rate; + q->step = (1/rate)*RESAMPLE_ARB_N; +} + +// Resample a block of input data +int resample_arb_compute(resample_arb_t *q, cf_t *input, cf_t *output, int n_in){ + int cnt = 0; + int n_out = 0; + int idx = 0; + + while(cnt < n_in) + { + *output = dot_prod(q->reg, polyfilt[idx], RESAMPLE_ARB_M); + output++; + n_out++; + q->acc += q->step; + idx = (int)roundf(q->acc); + while(idx >= RESAMPLE_ARB_N){ + q->acc -= RESAMPLE_ARB_N; + idx -= RESAMPLE_ARB_N; + if(cnt < n_in) + push(q, input[cnt++]); + } + } + return n_out; +} diff --git a/lte/lib/resampling/test/CMakeLists.txt b/lte/lib/resampling/test/CMakeLists.txt new file mode 100644 index 000000000..d2b6bd0f1 --- /dev/null +++ b/lte/lib/resampling/test/CMakeLists.txt @@ -0,0 +1,35 @@ +# +# Copyright 2012-2013 The libLTE Developers. See the +# COPYRIGHT file at the top-level directory of this distribution. +# +# This file is part of the libLTE library. +# +# libLTE is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as +# published by the Free Software Foundation, either version 3 of +# the License, or (at your option) any later version. +# +# libLTE is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# A copy of the GNU Lesser General Public License can be found in +# the LICENSE file in the top-level directory of this distribution +# and at http://www.gnu.org/licenses/. +# + +######################################################################## +# RESAMPLING TEST +######################################################################## + +ADD_EXECUTABLE(resample_arb_test resample_arb_test.c) +TARGET_LINK_LIBRARIES(resample_arb_test lte) + +ADD_EXECUTABLE(resample_arb_bench resample_arb_bench.c) +TARGET_LINK_LIBRARIES(resample_arb_bench lte) + +ADD_TEST(resample resample_arb_test) + + + diff --git a/lte/lib/resampling/test/resample_arb_bench.c b/lte/lib/resampling/test/resample_arb_bench.c new file mode 100644 index 000000000..4a7d20b62 --- /dev/null +++ b/lte/lib/resampling/test/resample_arb_bench.c @@ -0,0 +1,38 @@ +#include +#include +#include +#include +#include +#include + +#include "lte.h" +#include "lte/resampling/resample_arb.h" + +typedef _Complex float cf_t; + +int main(int argc, char **argv) { + int N=10000000; + float rate = 24.0/25.0; + cf_t *in = malloc(N*sizeof(cf_t)); + cf_t *out = malloc(N*sizeof(cf_t)); + + for(int i=0;i +#include +#include +#include +#include +#include + +#include "lte.h" +#include "lte/resampling/resample_arb.h" + +typedef _Complex float cf_t; + +int main(int argc, char **argv) { + int N = 100; // Number of sinwave samples + int delay = 5; // Delay of our resampling filter + float down = 25.0; // Downsampling rate + + for(int up=1;up diff && pre != post){ + printf("Interpolation failed at index %f", idx); + exit(-1); + } + } + + + free(in); + free(out); + } + + printf("Ok\n"); + exit(0); +} From ae50c990eca8b82d677ed00da4f8998b3f8e03a4 Mon Sep 17 00:00:00 2001 From: Paul Sutton Date: Wed, 16 Apr 2014 17:06:34 +0100 Subject: [PATCH 2/2] Adding matlab files for arbitrary resampler --- matlab/resampler/arb_filter.mat | Bin 0 -> 1475 bytes matlab/resampler/arb_resample_linear.m | 46 ++++++++++++++++++++++++ matlab/resampler/arb_resample_nearest.m | 37 +++++++++++++++++++ matlab/resampler/arb_resample_test.m | 33 +++++++++++++++++ 4 files changed, 116 insertions(+) create mode 100644 matlab/resampler/arb_filter.mat create mode 100644 matlab/resampler/arb_resample_linear.m create mode 100644 matlab/resampler/arb_resample_nearest.m create mode 100644 matlab/resampler/arb_resample_test.m diff --git a/matlab/resampler/arb_filter.mat b/matlab/resampler/arb_filter.mat new file mode 100644 index 0000000000000000000000000000000000000000..735fbc233271f5701268d9738ba9ac073a1407c4 GIT binary patch literal 1475 zcmV;!1w8sqK~zjZLLfCRFd$7qR4ry{Y-KDUP;6mzW^ZzBIv__(PFO)UG%O%Pa%Ew3 zWn>_4ZaN@Tb!8wyaB?6qH6SrIIyE*rH8vnJFflYBARr(hARr(hARr(hARr(hARr(h zARr(hARr(hARr(hARr(hARr(B00000000000ZB~{0000x1pokeoJEy;RLp4@$EP|f zX`}77vGc8X0c5vrIwI%nYJBerVS%H(IyGog~`$dO>Id$-H4i! zE>3H65@TJPbl7EUv39qwoj>M1zq$N=@B2L8=kqZW2m}ts0)gTC_5Jei`p;{`@U@=c zzc)RBfxt6nt6-#H_>19}v}1ySheH78Wk0gLU*yLNUccBGc+8*I6-}R}-4e*_nqvYC zdV+ZVEqQ0y!w^YtivE9bm7rQxk-<-9-_ z`-QuWg4@PIlAY&2O(;d?=S%CHI&<_u&fZB%6tTi^#Imq(yr= zn1sS+&)Hu`(suLB8D~>v)Yb0orms#UlawoVzianU+ehka+r3jrv(IUczw{tYwN%|c z?vqYSvey@?oDY-#{osKz+boKeG=xoiag4OHHuW~Cvq>n)TNN-Zmr~6|ny&SEG(wlS zGBW-IJ)Yd%a6aZFnQhbmLm^g?*wA~vP$B%IOCf| zHG%W&X9*6Gq`msN;gb{!I^UA;Kqe=z@!x^uyuyZnqMZ>vXS)R zuF(2gZrN>iLPd3)Hu$E}D5Z{__bfc*{!<-K)YA{2{Qf%8-tub0{5oEqb0hxn$yyFC zQ5s2FYxtX34`We9HIJ3JTLh>tb9lAEl3O7c*&)e%$zW1BHx@3Gy)sktlY&8;WWz!p zzc|UKuRe!A&(MujL@Bt|nv!hSq>+Bq&{9RyDQeS8muN4l>FpU|wzGK^dC44GTElC} z?#A~+cSbdkYo2$h@^%yXj@!5`KCG3ZgZ#T<2HU9ocz9afIAzE@t;qrvGCYe!sci6 za$juKoxOczIzHKOsz^uTkfFq`3LPo`I=cRiT|bHQ9feKt{iN~LRh|C1pRCu;2ytxx zf5qqc-G~1T-v{@_bMRd31N*{0v2UCM=fXL0ZqxyFL7h-H)Dd+>ol$r60ewNA&^PoE zeMO(qcjN%MKu(Yw#xkk>Bd&~jm0&{}7!5m?(FlU%M%pv9y zbBeje9AmCA=a_qN09*hkzzuK&Tmfgm9dHO-0;j+&a12}n=fFL15L^T&!A)=!Tm@&r zU2qs&2B*Poa2#9*=fQn=0A7G6;0<^LUV&%e9e4;{f~Vjucnn^H=iohf5MKP?$zgB8 dqwp#`3-7|i@G?9NZ^Ps8Iy?{W{|&w3`HXB8)ZG98 literal 0 HcmV?d00001 diff --git a/matlab/resampler/arb_resample_linear.m b/matlab/resampler/arb_resample_linear.m new file mode 100644 index 000000000..4bfb4df03 --- /dev/null +++ b/matlab/resampler/arb_resample_linear.m @@ -0,0 +1,46 @@ +function out = arb_resample_linear(sig, rate) + +N = 32; +M = 8; +step = (1/rate)*N; + +load('arb_filter.mat'); + +figure;plot(Num);title('Filter impulse response'); +[h,w] = freqz(Num, 1); +figure;plot(20*log10(abs(h)));title('Filter freq response'); + +% Create polyphase partition +poly = reshape(Num, N, M); + +% Filter +sig = [zeros(1,(M/2)-1) sig]; +k=0; +acc=0; +index=0; +frac=0; +out = []; +while k < length(sig)-M + sig_reg = fliplr(sig(k+1:k+M)); + filt_reg1 = poly(index+1, :); + filt_reg2 = poly(mod(index+1,N)+1, :); + res1 = sig_reg*filt_reg1'; + res2 = sig_reg*filt_reg2'; + + if index+1 == 32 + res = res1; + else + res = res1 + (res2-res1)*frac; + end + + out = [out res]; + + acc = acc+step; + index = fix(acc); + while index >= N + acc = acc - N; + index = index - N; + k = k+1; + end + frac = abs(acc-index); +end diff --git a/matlab/resampler/arb_resample_nearest.m b/matlab/resampler/arb_resample_nearest.m new file mode 100644 index 000000000..0601aa169 --- /dev/null +++ b/matlab/resampler/arb_resample_nearest.m @@ -0,0 +1,37 @@ +function out = arb_resample_nearest(sig, rate) + +N = 32; +M = 8; +step = (1/rate)*N; + +load('arb_filter.mat'); + +figure;plot(Num);title('Filter impulse response'); +[h,w] = freqz(Num, 1); +figure;plot(20*log10(abs(h)));title('Filter frequency response'); + +% Create polyphase partition +poly = reshape(Num, N, M); + +% Filter +sig = [zeros(1,(M/2)-1) sig]; +k=0; +acc=0; +index=0; +frac=0; +out = []; +while k < length(sig)-M + sig_reg = fliplr(sig(k+1:k+M)); + filt_reg1 = poly(index+1, :); + res = sig_reg*filt_reg1'; + + out = [out res]; + + acc = acc+step; + index = round(acc); + while index >= N + acc = acc - N; + index = index - N; + k = k+1; + end +end \ No newline at end of file diff --git a/matlab/resampler/arb_resample_test.m b/matlab/resampler/arb_resample_test.m new file mode 100644 index 000000000..b6d661da4 --- /dev/null +++ b/matlab/resampler/arb_resample_test.m @@ -0,0 +1,33 @@ +close all +clear all + +up = 24; +down = 25; +d_rate = up/down; +Fs = 100; % Arbitrary sample rate (used for displays) +Fsin = 1; + +% Create a sine wave +t = 0:1/Fs:1-1/Fs; +sig = sin(2*pi*t); + +out = arb_resample_nearest(sig,d_rate); + +% matlab resample for comparison +out2 = resample(sig, up, down); +figure;hold on;title('Ours and matlabs'); +l = min(length(out), length(out2)); +stem(out(1:l)); +stem(out2(1:l), 'r', 'filled'); +diff = out2(1:l)-out(1:l); +figure;plot(diff);title('Difference between ours and matlabs'); + +figure; hold on;title('Original and resampled - no time scaling'); +stem(sig); +stem(out, 'r', 'filled'); + +% Time align and plot +figure;hold on;title('Original and resampled - with time scaling'); +stem((1:75)/Fs,real(sig(1:75))); +stem((1:72)/(Fs*d_rate),real(out(1:72)),'r','filled'); +xlabel('Time (sec)');ylabel('Signal value'); \ No newline at end of file