Scheduled service maintenance on November 22


On Friday, November 22, 2024, between 06:00 CET and 18:00 CET, GIN services will undergo planned maintenance. Extended service interruptions should be expected. We will try to keep downtimes to a minimum, but recommend that users avoid critical tasks, large data uploads, or DOI requests during this time.

We apologize for any inconvenience.

uTest_FiltFiltM.m 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. function uTest_FiltFiltM(doSpeed)
  2. % Unit test: FiltFiltM
  3. % This is a routine for automatic testing. It is not needed for processing and
  4. % can be deleted or moved to a folder, where it does not bother.
  5. %
  6. % uTest_FiltFiltM(doSpeed)
  7. % INPUT:
  8. % doSpeed: If ANY(doSpeed) is TRUE, the speed is measured. Optional.
  9. % OUTPUT:
  10. % On failure the test stops with an error.
  11. %
  12. % Tested: Matlab 6.5, 7.7, 7.8, WinXP
  13. % Author: Jan Simon, Heidelberg, (C) 2009-2011 matlab.THISYEAR(a)nMINUSsimon.de
  14. % $JRev: R-k V:010 Sum:VKPp090JCPL7 Date:19-Jul-2011 19:40:07 $
  15. % $License: BSD (use/copy/change/redistribute on own risk, mention the author) $
  16. % $File: Tools\UnitTests_\uTest_FiltFiltM.m $
  17. % Init: ========================================================================
  18. ErrHead = ['JSimon:', mfilename, ':TestFailed'];
  19. if nargin == 0 || any(doSpeed)
  20. TestTime = 2.0; % sec
  21. else
  22. TestTime = 0.5; % sec
  23. end
  24. % ==============================================================================
  25. disp(['==== Test FiltFiltM ', datestr(now, 0)]);
  26. disp([' Version: ', which('FiltFiltM')]);
  27. pause(0.01); % Flush events
  28. fprintf('\nKnown answer tests:\n');
  29. B = [];
  30. A = [];
  31. Y = FiltFiltM(B, A, []);
  32. if ~isempty(Y)
  33. error(ErrHead, ['*** ', mfilename, ': Bad reply for empty signal']);
  34. end
  35. disp(' ok: all input empty');
  36. B = [];
  37. A = [];
  38. X = rand(1000, 1);
  39. Y = FiltFiltM(B, A, X);
  40. if ~isempty(Y)
  41. error(ErrHead, ['*** ', mfilename, ': Bad reply for empty parameters']);
  42. end
  43. disp(' ok: empty parameters');
  44. % [B, A] = ButterParam(2, 0.2, 'low')
  45. B = [0.06745527, 0.1349105, 0.06745527];
  46. A = [1, -1.142981, 0.4128016];
  47. Y = FiltFiltM(B, A, []);
  48. if ~isempty(Y)
  49. error(ErrHead, ...
  50. ['*** ', mfilename, ': Bad reply for empty signal with parameters']);
  51. end
  52. disp(' ok: empty signal');
  53. Y = FiltFiltM(B, A, X);
  54. Z = filtfilt(B, A, X);
  55. if ~isequal(size(Y), size(Z)) || any(abs(Y - Z) > 10 * eps)
  56. error(ErrHead, ...
  57. ['*** ', mfilename, ': Bad result for [1000 x 1]']);
  58. end
  59. disp(' ok: [N x 1] vector');
  60. Xt = reshape(X, 1, []);
  61. Y = FiltFiltM(B, A, Xt);
  62. if ~isequal(size(Y), size(Xt)) || any(abs(Y(:) - Z(:)) > 10 * eps)
  63. error(ErrHead, ...
  64. ['*** ', mfilename, ': Bad result for [1 x 1000]']);
  65. end
  66. disp(' ok: [1 x N] vector');
  67. X = [X, X];
  68. Y = FiltFiltM(B, A, X);
  69. Z = filtfilt(B, A, X);
  70. if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
  71. error(ErrHead, ...
  72. ['*** ', mfilename, ': Bad result for [1000 x 2]']);
  73. end
  74. disp(' ok: 2D array, 1st dim');
  75. X = transpose(X);
  76. Y = FiltFiltM(B, A, X, 2);
  77. Z = transpose(Z);
  78. if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
  79. error(ErrHead, ...
  80. ['*** ', mfilename, ': Bad result for [2 x 1000], 2nd dim']);
  81. end
  82. disp(' ok: 2D array, 2nd dim');
  83. X = rand(20, 30, 40);
  84. Y = FiltFiltM(B, A, X);
  85. Z = filtfilt(B, A, X);
  86. if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
  87. error(ErrHead, ...
  88. ['*** ', mfilename, ': Bad result for [20 x 30 x 40]']);
  89. end
  90. Y = FiltFiltM(B, A, X, 2);
  91. Z = ipermute(filtfilt(B, A, permute(X, [2,1,3])), [2,1,3]);
  92. if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
  93. error(ErrHead, ...
  94. ['*** ', mfilename, ': Bad result for [20 x 30 x 40], 2nd dim']);
  95. end
  96. Y = FiltFiltM(B, A, X, 3);
  97. Z = ipermute(filtfilt(B, A, permute(X, [3,1,2])), [3,1,2]);
  98. if ~isequal(size(Y), size(Z)) || any(abs(Y(:) - Z(:)) > 10 * eps)
  99. error(ErrHead, ...
  100. ['*** ', mfilename, ': Bad result for [20 x 30 x 40], 3rd dim']);
  101. end
  102. disp(' ok: 3D array, 1st, 2nd, 3rd dim');
  103. X = rand(1000, 1);
  104. Y = FiltFiltM(B, A, X);
  105. Z = FiltFiltM(B, A, reshape(X, 1, 1, []), []);
  106. if ~isequal(size(Z), [1, 1, numel(X)]) || any(abs(Y(:) - Z(:)) > 10 * eps)
  107. error(ErrHead, ['*** ', mfilename, ...
  108. ': Bad result for [1 x 1 x 1000], 1st non-singelton']);
  109. end
  110. disp(' ok: [1 x 1 x N] array, 1st non-singelton');
  111. % FILTER does not support SINGLES in Matlab 6.5:
  112. try
  113. y = filter(B, A, single(ones(1, 100))); %#ok<NASGU>
  114. FILTERforSINGLE = true;
  115. catch
  116. FILTERforSINGLE = false;
  117. lasterr('');
  118. end
  119. if FILTERforSINGLE
  120. X = rand(1000, 2);
  121. Y = FiltFiltM(B, A, X);
  122. Xs = single(X);
  123. Ys = FiltFiltM(B, A, Xs);
  124. Zs = filtfilt(B, A, Xs);
  125. if ~isequal(size(Ys), size(Zs))
  126. error(ErrHead, ['*** ', mfilename, ': Bad result for SINGLE']);
  127. end
  128. epsSingle = 1.192092895507813e-007;
  129. errFiltFiltM = max(abs(double(Ys(:)) - Y(:))) / epsSingle;
  130. errFILTFILT = max(abs(double(Zs(:)) - Y(:))) / epsSingle;
  131. if any(errFiltFiltM > 10)
  132. error(ErrHead, ['*** ', mfilename, ': Bad result for SINGLE']);
  133. end
  134. disp(' ok: SINGLE array');
  135. fprintf([' Difference to DOUBLE divided by EPS(SINGLE(1)):\n', ...
  136. ' FilterM: %g, FILTER: %g\n'], errFiltFiltM, errFILTFILT);
  137. else
  138. v = sscanf(version, '%d.', 2);
  139. fprintf(' ok: FILTER does not accept SINGLE in Matlab %d.%d\n', v);
  140. end
  141. % ------------------------------------------------------------------------------
  142. tooLazy = false;
  143. fprintf('\nProvoke problems:\n');
  144. try
  145. Y = FiltFiltM(B, A, rand(4)); %#ok<NASGU>
  146. tooLazy = true;
  147. catch
  148. disp(' ok: Too short signal in dim 1 caught.');
  149. end
  150. if tooLazy
  151. error(ErrHead, ['*** ', mfilename, ': Too short signal accepted.']);
  152. end
  153. try
  154. Y = FiltFiltM(B, A, rand(4), 2); %#ok<NASGU>
  155. tooLazy = true;
  156. catch
  157. disp(' ok: Too short signal in dim 2 caught.');
  158. end
  159. if tooLazy
  160. error(ErrHead, ['*** ', mfilename, ': Too short signal accepted.']);
  161. end
  162. try
  163. Y = FiltFiltM(B, A, rand(1, 100), 3); %#ok<NASGU>
  164. tooLazy = true;
  165. catch
  166. disp(' ok: Dim out of range caught.');
  167. end
  168. if tooLazy
  169. error(ErrHead, ['*** ', mfilename, ': Dim out of range accepted.']);
  170. end
  171. try
  172. Y = FiltFiltM(B, A, rand(1, 100), -3.1); %#ok<NASGU>
  173. tooLazy = true;
  174. catch
  175. disp(' ok: Not integer Dim caught.');
  176. end
  177. if tooLazy
  178. error(ErrHead, ['*** ', mfilename, ': Not integer Dim accepted.']);
  179. end
  180. % Time test: -------------------------------------------------------------------
  181. % Results on a Pentium-M 1500 MHz, 512MB RAM, WinXP, Matlab 2009a:
  182. % Number of loops to get about 2 seconds run time
  183. % 1000000 x 1: 6 loops, FILTFILT: 1.930 sec, FiltFiltM: 0.385 sec ==> 20.0%
  184. % 100000 x 1: 70 loops, FILTFILT: 2.077 sec, FiltFiltM: 0.488 sec ==> 23.5%
  185. % 10000 x 10: 82 loops, FILTFILT: 1.996 sec, FiltFiltM: 0.600 sec ==> 30.0%
  186. % 1000 x 100: 50 loops, FILTFILT: 2.761 sec, FiltFiltM: 0.518 sec ==> 18.7%
  187. % 100 x 100: 100 loops, FILTFILT: 1.935 sec, FiltFiltM: 0.079 sec ==> 4.1%
  188. % 100 x 1000: 12 loops, FILTFILT: 2.303 sec, FiltFiltM: 0.130 sec ==> 5.6%
  189. % A 4th order Butterworth filter: [B, A] = Butter(4, 0.25, 'low')
  190. B = [0.0102094807912032, 0.0408379231648126, 0.0612568847472189, ...
  191. 0.0408379231648126, 0.0102094807912032];
  192. A = [1.0, -1.96842778693852, 1.73586070920889, -0.724470829507363, ...
  193. 0.120389599896245];
  194. fprintf('\n== Speed test with Butterworth filter of order %d:\n', ...
  195. length(B) - 1);
  196. fprintf('Number of loops determined for about %g seconds run time\n', TestTime);
  197. TestSize = {[1e6, 1], [1e5, 1], [1e4, 10], [1e3, 100], [100, 100], [100, 1e3]};
  198. for iTest = 1:length(TestSize)
  199. % Create test data:
  200. aSize = TestSize{iTest};
  201. x = rand(aSize(1), aSize(2));
  202. msg = sprintf(' %d x %d:', aSize);
  203. fprintf('%-14s', msg);
  204. drawnow;
  205. % Run test of original function:
  206. iTime = cputime;
  207. nLoop = 0;
  208. while cputime - iTime < 1
  209. nLoop = nLoop + 1;
  210. origy = filtfilt(B, A, x); %#ok<NASGU>
  211. clear('origy');
  212. end
  213. nLoop = max(2, ceil(nLoop * TestTime));
  214. fprintf('%5d loops\n', nLoop);
  215. % Run test for vectorized function:
  216. tic;
  217. for i = 1:nLoop
  218. origy = filtfilt(B, A, x); %#ok<NASGU>
  219. clear('origy');
  220. end
  221. elapsed0 = toc;
  222. fprintf(' FILTFILT: %8.3f sec\n', elapsed0);
  223. % Run test for vectorized function:
  224. tic;
  225. for i = 1:nLoop
  226. newy = FiltFiltM(B, A, x); %#ok<NASGU>
  227. clear('newy');
  228. end
  229. elapsed1 = toc;
  230. fprintf(' FiltFiltM: %8.3f sec', elapsed1);
  231. fprintf(' ==> %.1f%%\n', 100 * elapsed1 / elapsed0);
  232. % Compare the results - usually the results are identical, but small round
  233. % off errors would be ok:
  234. origy = filtfilt(B, A, x);
  235. newy = FiltFiltM(B, A, x);
  236. if isequal(origy, newy)
  237. fprintf(' Results are identical\n\n');
  238. elseif all(abs(origy(:) - newy(:)) < 10 * eps)
  239. fprintf(' Results are equal within 10*eps\n\n');
  240. else
  241. error(ErrHead, 'Different results - DO NOT USE FiltFiltM!');
  242. end
  243. end
  244. % Bye:
  245. disp('== FiltFiltM passed the tests.');
  246. return;