roctave 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +674 -0
  3. data/README.md +33 -0
  4. data/ext/roctave/cu8_file_reader.c +331 -0
  5. data/ext/roctave/cu8_file_reader.h +30 -0
  6. data/ext/roctave/extconf.rb +6 -0
  7. data/ext/roctave/fir_filter.c +795 -0
  8. data/ext/roctave/fir_filter.h +29 -0
  9. data/ext/roctave/freq_shifter.c +410 -0
  10. data/ext/roctave/freq_shifter.h +29 -0
  11. data/ext/roctave/iir_filter.c +462 -0
  12. data/ext/roctave/iir_filter.h +29 -0
  13. data/ext/roctave/roctave.c +38 -0
  14. data/ext/roctave/roctave.h +27 -0
  15. data/lib/roctave.rb +168 -0
  16. data/lib/roctave/bilinear.rb +92 -0
  17. data/lib/roctave/butter.rb +87 -0
  18. data/lib/roctave/cheby.rb +180 -0
  19. data/lib/roctave/cu8_file_reader.rb +45 -0
  20. data/lib/roctave/dft.rb +280 -0
  21. data/lib/roctave/filter.rb +64 -0
  22. data/lib/roctave/finite_difference_coefficients.rb +73 -0
  23. data/lib/roctave/fir.rb +121 -0
  24. data/lib/roctave/fir1.rb +134 -0
  25. data/lib/roctave/fir2.rb +246 -0
  26. data/lib/roctave/fir_design.rb +311 -0
  27. data/lib/roctave/firls.rb +380 -0
  28. data/lib/roctave/firpm.rb +499 -0
  29. data/lib/roctave/freq_shifter.rb +47 -0
  30. data/lib/roctave/freqz.rb +233 -0
  31. data/lib/roctave/iir.rb +80 -0
  32. data/lib/roctave/interp1.rb +78 -0
  33. data/lib/roctave/plot.rb +748 -0
  34. data/lib/roctave/poly.rb +46 -0
  35. data/lib/roctave/roots.rb +73 -0
  36. data/lib/roctave/sftrans.rb +157 -0
  37. data/lib/roctave/version.rb +3 -0
  38. data/lib/roctave/window.rb +116 -0
  39. data/roctave.gemspec +79 -0
  40. data/samples/butter.rb +12 -0
  41. data/samples/cheby.rb +28 -0
  42. data/samples/dft.rb +18 -0
  43. data/samples/differentiator.rb +48 -0
  44. data/samples/differentiator_frequency_scaling.rb +52 -0
  45. data/samples/fft.rb +40 -0
  46. data/samples/finite_difference_coefficient.rb +53 -0
  47. data/samples/fir1.rb +13 -0
  48. data/samples/fir2.rb +14 -0
  49. data/samples/fir2_windows.rb +29 -0
  50. data/samples/fir2bank.rb +30 -0
  51. data/samples/fir_low_pass.rb +44 -0
  52. data/samples/firls.rb +77 -0
  53. data/samples/firpm.rb +78 -0
  54. data/samples/hilbert_transformer.rb +20 -0
  55. data/samples/hilbert_transformer_frequency_scaling.rb +47 -0
  56. data/samples/plot.rb +45 -0
  57. data/samples/stem.rb +8 -0
  58. data/samples/type1.rb +25 -0
  59. data/samples/type3.rb +24 -0
  60. data/samples/windows.rb +25 -0
  61. metadata +123 -0
@@ -0,0 +1,499 @@
1
+ ## Copyright (C) 2019 Théotime Bollengier <theotime.bollengier@gmail.com>
2
+ ##
3
+ ## This file is part of Roctave
4
+ ##
5
+ ## Roctave is free software: you can redistribute it and/or modify
6
+ ## it under the terms of the GNU General Public License as published by
7
+ ## the Free Software Foundation, either version 3 of the License, or
8
+ ## (at your option) any later version.
9
+ ##
10
+ ## Roctave is distributed in the hope that it will be useful,
11
+ ## but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ ## GNU General Public License for more details.
14
+ ##
15
+ ## You should have received a copy of the GNU General Public License
16
+ ## along with Roctave. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+
19
+ class Matrix
20
+ def puts
21
+ strings = Array.new(self.row_size){Array.new(self.column_size)}
22
+ (0 ... self.row_size).each do |i|
23
+ (0 ... self.column_size).each do |j|
24
+ strings[i][j] = self[i, j].round(4).to_s
25
+ end
26
+ end
27
+ maxstrlen = strings.flatten.collect{|s| s.length + 2}.max
28
+ Kernel.puts
29
+ (0 ... self.row_size).each do |i|
30
+ if i == 0 and i == self.row_size - 1 then
31
+ print ' ['
32
+ elsif i == 0 then
33
+ print ' ⎡'
34
+ elsif i == self.row_size - 1 then
35
+ print ' ⎣'
36
+ else
37
+ print ' ⎢'
38
+ end
39
+
40
+ (0 ... self.column_size).each do |j|
41
+ print strings[i][j].center(maxstrlen)
42
+ end
43
+
44
+ if i == 0 and i == self.row_size - 1 then
45
+ Kernel.puts ']'
46
+ elsif i == 0 then
47
+ Kernel.puts '⎤'
48
+ elsif i == self.row_size - 1 then
49
+ Kernel.puts '⎦'
50
+ else
51
+ Kernel.puts '⎥'
52
+ end
53
+ end
54
+ Kernel.puts
55
+ end
56
+ end
57
+
58
+
59
+ module Roctave
60
+ # @!group FIR filters
61
+
62
+ ##
63
+ # Weighted least-squares method for FIR filter approximation by optimization.
64
+ # Minimizes the square of the energy of the error function.
65
+ # @param n [Integer] The filter order
66
+ # @param f [Array<Float, Array<Float>, Range>] Frequency band edges, onced flattened, must be of even length
67
+ # @param a [Array<Float, Array<Float>, Range>] Magnitude at frequency bands. Each element must be a scalar (for the whole band), or a range or a two element array (for the two band edges of the band). Length +a+ == length +f+ / 2
68
+ # @param w [Array<Float, Array<Float>, Range] Weight at frequency bands. Each element must be a scalar (for the whole band), or a range or a two element array (for the two band edges of the band). Length +w+ == length +f+ / 2
69
+ # @param type [:odd_symmetry, :even_symmetry] Specify the symmetry of the filter. nil and :even_symmetry are the same and default, for type 1 and 2 filters, :odd_symmetry is for type 3 and 4 filters.
70
+ # @param grid [Integer] The length of the grid over which the frequency response is evaluated. Defaults to 16, for an interpolation on 16*+n+.
71
+ # @return [Array<Float>] The filter coefficients B
72
+ def self.firpm (n, f, a, *args)
73
+ raise ArgumentError.new "Expecting no more than 6 arguments" if args.length > 3
74
+
75
+ n = [1, n.to_i].max
76
+
77
+ case f
78
+ when Array
79
+ when Range
80
+ f = [f]
81
+ else
82
+ raise ArgumentError.new "F must be an array or a range"
83
+ end
84
+ f.collect! do |e|
85
+ case e
86
+ when Range
87
+ [e.begin.to_f, e.end.to_f]
88
+ when Array
89
+ raise ArgumentError.new "Elements of F which are arrays must have exaclty two floats" unless (e.length == 2 and e.first.kind_of?(Float) and e.last.kind_of?(Float))
90
+ [e.first.to_f, e.last.to_f]
91
+ else
92
+ e.to_f
93
+ end
94
+ end
95
+ f = f.flatten
96
+ raise ArgumentError.new "At least one frequency band must be specified!" if f.empty?
97
+ raise ArgumentError.new "Once flattened, F must have an even number of frequency bands!" unless (f.length & 1) == 0
98
+ raise ArgumentError.new "F must have at least one band!" unless f.length >= 2
99
+ f.each do |e|
100
+ raise ArgumentError.new "Frequency band edges must be in the range [0, 1]" unless (e >= 0.0 and e <= 1.0)
101
+ end
102
+ (1...f.length).each do |i|
103
+ raise ArgumentError.new "Frequecy band edges must be strictly increasing" if f[i-1] >= f[i]
104
+ end
105
+
106
+ case a
107
+ when Array
108
+ when Range
109
+ [a]
110
+ when Numeric
111
+ [a]
112
+ else
113
+ raise ArgumentError.new "A must be an array or a range"
114
+ end
115
+ raise ArgumentError.new "Length of A must be half the length of F" unless a.length == f.length/2
116
+ a.collect! do |e|
117
+ case e
118
+ when Range
119
+ [e.begin.to_f.abs, e.end.to_f.abs]
120
+ when Array
121
+ raise ArgumentError.new "Elements of A which are arrays must have at least two floats" if e.length < 2
122
+ e.collect{|v| v.to_f}
123
+ else
124
+ [e.to_f.abs, e.to_f.abs]
125
+ end
126
+ end
127
+
128
+ w = nil
129
+ type = :even_symmetry
130
+ grid = 16
131
+
132
+ args.each.with_index do |arg, i|
133
+ case arg
134
+ when :even_symmetry
135
+ type = :even_symmetry
136
+ when :odd_symmetry
137
+ type = :odd_symmetry
138
+ when Numeric
139
+ grid = [1, arg.to_i].max
140
+ STDERR.puts "WARNING: recommended grid sampling factor are integers in the range [8, 16]." unless Range.new(8, 16).include?(grid)
141
+ when Array
142
+ raise ArgumentError.new "Length of W must be half the length of F" unless arg.length == f.length/2
143
+ w = arg.collect do |e|
144
+ case e
145
+ when Range
146
+ [e.begin.to_f.abs, e.end.to_f.abs]
147
+ when Array
148
+ raise ArgumentError.new "Elements of W which are arrays must have at least two floats" if e.length < 2
149
+ e.collect{|v| v.to_f}
150
+ else
151
+ [e.to_f.abs, e.to_f.abs]
152
+ end
153
+ end
154
+ else
155
+ raise ArgumentError.new "Argument #{i+4} must either be :odd_symmetry, :even_symmetry, an array of weight or the grid sampling (Integer)"
156
+ end
157
+ end
158
+
159
+ w = (f.length / 2).times.collect{[1.0, 1.0]} if w.nil?
160
+
161
+ bands = (0 ... a.length).collect do |i|
162
+ {
163
+ frequencies: Range.new(f[2*i], f[2*i+1]),
164
+ amplitudes: a[i],
165
+ weights: w[i]
166
+ }
167
+ end
168
+ band_edges = bands.collect{|h| [h[:frequencies].begin, h[:frequencies].end]}.flatten.collect{|v| v*Math::PI}.uniq
169
+
170
+ ## Create the sampling grid by interpolation ##
171
+ nb_sample_points = grid*n
172
+ constrained_frequency_amount = bands.inject(0.0){|m, h| m + h[:frequencies].end - h[:frequencies].begin}
173
+ # debug_amp_plot_args = []
174
+ # debug_weight_plot_args = []
175
+ bands.each do |band|
176
+ # debug_amp_plot_args << Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, band[:amplitudes].length)
177
+ # debug_amp_plot_args << band[:amplitudes].collect{|e| e}
178
+ # debug_amp_plot_args << '-+b'
179
+ # debug_weight_plot_args << Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, band[:weights].length)
180
+ # debug_weight_plot_args << band[:weights].collect{|e| e}
181
+ # debug_weight_plot_args << '-+b'
182
+
183
+ fi = Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, [2, ((band[:frequencies].end - band[:frequencies].begin) * nb_sample_points / constrained_frequency_amount).ceil].max)
184
+ ai = Roctave.interp1(Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, band[:amplitudes].length), band[:amplitudes], fi)
185
+ wi = Roctave.interp1(Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, band[:weights].length), band[:weights], fi)
186
+
187
+ # debug_amp_plot_args << fi.collect{|e| e}
188
+ # debug_amp_plot_args << ai.collect{|e| e}
189
+ # debug_amp_plot_args << '-xr'
190
+ # debug_weight_plot_args << fi.collect{|e| e}
191
+ # debug_weight_plot_args << wi.collect{|e| e}
192
+ # debug_weight_plot_args << '-xr'
193
+
194
+ band[:frequencies] = fi.collect{|v| v*Math::PI}
195
+ band[:amplitudes] = ai
196
+ band[:weights] = wi
197
+ end
198
+ nb_sample_points = bands.inject(0.0){|m, h| m + h[:frequencies].length}
199
+
200
+
201
+ ## Filter type ##
202
+ if type == :even_symmetry then
203
+ if (n & 1) == 0 then
204
+ filter_type = 1
205
+ beta = 0.0
206
+ q = -> w { 1.0 }
207
+ l = n / 2
208
+ coefs_from_p = -> p {
209
+ (-l .. l).collect{|m| m.abs}.collect do |m|
210
+ if m == 0 then
211
+ p[m, 0]
212
+ else
213
+ p[m, 0] / 2.0
214
+ end
215
+ end
216
+ }
217
+ else
218
+ filter_type = 2
219
+ beta = 0.0
220
+ q = -> w { Math.cos(w/2.0) }
221
+ l = (n - 1) / 2
222
+ coefs_from_p = -> p {
223
+ id = (1..l+1).to_a
224
+ (id.reverse + id).collect{ |m|
225
+ if m == 1 then
226
+ p[0, 0] + 0.5*p[1, 0]
227
+ elsif m == l+1 then
228
+ 0.5*p[l, 0]
229
+ else
230
+ 0.5*(p[m-1, 0] + p[m, 0])
231
+ end
232
+ }.collect{|v| v/2.0}
233
+ }
234
+ end
235
+ else
236
+ if (n & 1) == 0 then
237
+ filter_type = 3
238
+ beta = Math::PI/2
239
+ q = -> w { Math.sin(w) }
240
+ l = n / 2 - 1
241
+ coefs_from_p = -> p {
242
+ id = (1..l+1).to_a
243
+ (id.reverse + [0] + id).collect{ |m|
244
+ if m == 0 then
245
+ 0.0
246
+ elsif m == 1 then
247
+ p[0, 0] - 0.5*p[2, 0]
248
+ elsif m >= l then
249
+ 0.5*p[m-1, 0]
250
+ else
251
+ 0.5*(p[m-1,0] - p[m+1, 0])
252
+ end
253
+ }.collect.with_index{ |v, i|
254
+ if i < l + 1 then
255
+ v/2.0
256
+ else
257
+ -v/2.0
258
+ end
259
+ }
260
+ }
261
+ else
262
+ filter_type = 4
263
+ beta = Math::PI/2
264
+ q = -> w { Math.sin(w/2.0) }
265
+ l = (n - 1) / 2
266
+ coefs_from_p = -> p {
267
+ id = (1..l+1).to_a
268
+ (id.reverse + id).collect{ |m|
269
+ if m == 1 then
270
+ p[0, 0] - 0.5*p[1, 0]
271
+ elsif m == l+1 then
272
+ 0.5*p[l, 0]
273
+ else
274
+ 0.5*(p[m-1, 0] - p[m, 0])
275
+ end
276
+ }.collect.with_index{ |v, i|
277
+ if i < l + 1 then
278
+ v/2.0
279
+ else
280
+ -v/2.0
281
+ end
282
+ }
283
+ }
284
+ end
285
+ end
286
+ # puts "Filter Type #{case filter_type; when 1 then 'I'; when 2 then 'II'; when 3 then 'III'; else 'IV' end}"
287
+
288
+
289
+ ## Create the matrices ##
290
+ frequencies = bands.inject([]){|m, h| m + h[:frequencies]}
291
+ amplitudes = bands.inject([]){|m, h| m + h[:amplitudes]}
292
+ weights = bands.inject([]){|m, h| m + h[:weights]}
293
+
294
+ band_edges_faw = []
295
+ frequencies.each.with_index do |v, i|
296
+ if band_edges.include?(v) then
297
+ band_edges_faw << {f: v, a: amplitudes[i], w: weights[i]}
298
+ end
299
+ end
300
+
301
+ # ## (i) Initialize an estimate for the extreme frequencies w0, w1, ..., wL+1 by selecting (L+2)
302
+ # ## equally spaced frequencies at the bands specified for the desired filter.
303
+ #
304
+ # nb_test_points = l+2
305
+ # extreme_frequencies = :wq
306
+ # constrained_frequency_amount = bands.inject(0.0){|m, h| m + h[:frequencies].end - h[:frequencies].begin}
307
+ # bands.each do |band|
308
+ # fi = Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, [2, ((band[:frequencies].end - band[:frequencies].begin) * nb_sample_points / constrained_frequency_amount).ceil].max)
309
+ # ai = Roctave.interp1(Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, band[:amplitudes].length), band[:amplitudes], fi)
310
+ # wi = Roctave.interp1(Roctave.linspace(band[:frequencies].begin, band[:frequencies].end, band[:weights].length), band[:weights], fi)
311
+ #
312
+ # band[:frequencies] = fi.collect{|v| v*Math::PI}
313
+ # band[:amplitudes] = ai
314
+ # band[:weights] = wi
315
+ # end
316
+ # nb_sample_points = bands.inject(0.0){|m, h| m + h[:frequencies].length}
317
+ # ####
318
+
319
+
320
+ mat_Wq2 = Matrix.build(nb_sample_points) do |i, j|
321
+ if i == j then
322
+ (weights[i] * q.call(frequencies[i]))**2
323
+ else
324
+ 0.0
325
+ end
326
+ end
327
+
328
+ mat_dq = Matrix.build(nb_sample_points, 1) do |i|
329
+ qw = q.call(frequencies[i])
330
+ qw = 0.000000001 if qw == 0.0
331
+ amplitudes[i] / qw
332
+ end
333
+
334
+ mat_U = Matrix.build(nb_sample_points, l + 1) do |i, j|
335
+ Math.cos(j * frequencies[i])
336
+ end
337
+
338
+ mat_UT_times_mat_Wq2 = mat_U.transpose * mat_Wq2
339
+ p = (mat_UT_times_mat_Wq2 * mat_U).inverse * (mat_UT_times_mat_Wq2 * mat_dq)
340
+
341
+ p.puts
342
+
343
+ b = coefs_from_p.call(p)
344
+
345
+ ###
346
+ # Matrix.column_vector(b).puts
347
+ #
348
+ # if filter_type == 1 or filter_type == 3 then
349
+ # Roctave.stem((-n/2..n/2).to_a, b, :filled, grid: true)
350
+ # else
351
+ # Roctave.stem((n+1).times.collect{|i| i - (n+1)/2.0 + 0.5}, b, :filled, grid: true)
352
+ # end
353
+ #
354
+ # r2 = Roctave.dft(b, 2048)
355
+ # h2 = r2[0...1024].abs
356
+ # p2 = r2[0...1024].arg
357
+ # p2 = Roctave.unwrap(p2)
358
+ # w2 = Roctave.linspace(0, 1, 1024)
359
+ # debug_amp_plot_args << w2
360
+ # debug_amp_plot_args << h2
361
+ # debug_amp_plot_args << '-g;Response;'
362
+ #
363
+ # #Roctave.plot(*debug_weight_plot_args, title: 'Target weights', xlim: (0 .. 1), grid: true)
364
+ # Roctave.plot(*debug_amp_plot_args, title: 'Target filter magnitude response', xlim: (0 .. 1), grid: true)
365
+ # Roctave.plot(w2, h2.collect{|v| 10*Math.log10(v)}, xlabel: 'Normalized frequency', ylabel: 'Magnitude response (dB)', grid: true, title: 'Magnitude')
366
+ # Roctave.plot(w2, p2, grid: true, title: 'Phase')
367
+ ###
368
+
369
+ # Evaluate the response
370
+ p_w = -> fre {
371
+ (0..l).inject(0.0) do |m, i|
372
+ m + p[i,0]*Math.cos(fre*i)
373
+ end
374
+ }
375
+ alpha = n / 2.0
376
+ # freq = Roctave.linspace(0, Math::PI, 1024)
377
+ # resp = freq.collect{|v| Complex.polar(1.0, -alpha*v - beta)*q.call(v)*p_w.call(v)}
378
+ # Roctave.plot(freq.collect{|v| v/Math::PI}, resp.abs, title: 'Evaluated response', grid: true)
379
+
380
+ # Evaluate the error
381
+ error = frequencies.length.times.collect do |i|
382
+ weights[i]*(amplitudes[i] - q.call(frequencies[i])*p_w.call(frequencies[i]))
383
+ end
384
+ #error.collect!{|v| v.abs}
385
+
386
+ i = 0
387
+ loop do
388
+ maximum_freq = []
389
+ maximum_err = []
390
+ maximum_wei = []
391
+ maximum_amp = []
392
+ (1...frequencies.length - 1).each do |i|
393
+ if (error[i-1] < error[i] and error[i+1] < error[i]) or (error[i-1] > error[i] and error[i+1] > error[i]) then
394
+ maximum_freq << frequencies[i]
395
+ maximum_err << error[i]
396
+ maximum_wei << weights[i]
397
+ maximum_amp << amplitudes[i]
398
+ end
399
+ end
400
+
401
+ #Roctave.plot(frequencies, error, ';Error;', maximum_freq, maximum_err, 'o;mamimums;', title: 'Evaluated error', grid: true, xlim: [0, Math::PI])
402
+
403
+ maximum_freq_and_error = (0...maximum_freq.length).collect{|i|
404
+ {f: maximum_freq[i], e: maximum_err[i], a: maximum_amp[i], w: maximum_wei[i]}
405
+ }.reject{|h| band_edges.include?(h[:f])}.sort_by{|h| h[:e]}.reverse
406
+ l_plus_two_extremal = (band_edges_faw + maximum_freq_and_error[(0...(l+2 - band_edges_faw.length))]).sort_by{|h| h[:f]}
407
+ raise "Couldn't get #{l+2} extremals!" if (l_plus_two_extremal.length != l+2 or l_plus_two_extremal.include?(nil))
408
+ l_plus_two_extremal_frequencies = l_plus_two_extremal.collect{|h| h[:f]}
409
+ l_plus_two_extremal_amplitudes = l_plus_two_extremal.collect{|h| h[:a]}
410
+ l_plus_two_extremal_weights = l_plus_two_extremal.collect{|h| h[:w]}
411
+
412
+ ###
413
+
414
+ ak = (0 ... l+2).collect do |i|
415
+ (0 ... l+2).inject(1.0) do |m, j|
416
+ if j == i then
417
+ m
418
+ else
419
+ m / (Math.cos(l_plus_two_extremal_frequencies[i]) - Math.cos(l_plus_two_extremal_frequencies[j]))
420
+ end
421
+ end
422
+ end
423
+ deltatruc_numerator = (0 ... l+2).inject(0.0) do |m, i|
424
+ m + ak[i] * l_plus_two_extremal_amplitudes[i] / q.call(l_plus_two_extremal_frequencies[i])
425
+ end
426
+ deltatruc_denominator = (0 ... l+2).inject(0.0) do |m, i|
427
+ m + (-1)**i * ak[i] / l_plus_two_extremal_weights[i] * q.call(l_plus_two_extremal_frequencies[i])
428
+ end
429
+ deltatruc = deltatruc_numerator / deltatruc_denominator
430
+ puts "d_num = #{deltatruc_numerator}"
431
+ puts "d_den = #{deltatruc_denominator}"
432
+ puts "d = #{deltatruc}"
433
+
434
+
435
+
436
+ ## Interpolate p(w) ##
437
+
438
+ resp_interpolate = frequencies.collect.with_index do |freq, i|
439
+ k = l_plus_two_extremal_frequencies.index(freq)
440
+ if k then
441
+ amplitudes[i] - (((-1)**k) * deltatruc / weights[i])
442
+ else
443
+ beta_k = ak.collect.with_index{|v, k| v*(Math.cos(l_plus_two_extremal_frequencies[k]) - Math.cos(l_plus_two_extremal_frequencies[l+1]))}
444
+ betai_sur_machin = (0..l).collect do |j|
445
+ beta_k[j] / (Math.cos(freq) - Math.cos(l_plus_two_extremal_frequencies[j]))
446
+ end
447
+ den = betai_sur_machin.inject(&:+)
448
+ num = (0..l).inject(0.0) do |m, j|
449
+ m + betai_sur_machin[j] * ((l_plus_two_extremal_amplitudes[j] / q.call(l_plus_two_extremal_frequencies[j])) - (((-1)**j) * deltatruc / (l_plus_two_extremal_weights[j] * q.call(l_plus_two_extremal_frequencies[j]))))
450
+ end
451
+ q.call(freq) * (num / den)
452
+ end
453
+ end
454
+ ######################
455
+
456
+ i += 1
457
+
458
+ debug_plot_args = []
459
+ (0 ... band_edges_faw.length/2).each do |i|
460
+ debug_plot_args << [band_edges_faw[i*2][:f], band_edges_faw[i*2+1][:f]]
461
+ debug_plot_args << [band_edges_faw[i*2][:a], band_edges_faw[i*2+1][:a]]
462
+ debug_plot_args << "-xb#{(i == 0) ? ';Target;' : ''}"
463
+
464
+ debug_plot_args << [band_edges_faw[i*2][:f], band_edges_faw[i*2+1][:f]]
465
+ debug_plot_args << [band_edges_faw[i*2][:a] + deltatruc, band_edges_faw[i*2+1][:a] + deltatruc]
466
+ debug_plot_args << "-k#{(i == 0) ? ';Delta;' : ''}"
467
+ debug_plot_args << [band_edges_faw[i*2][:f], band_edges_faw[i*2+1][:f]]
468
+ debug_plot_args << [band_edges_faw[i*2][:a] - deltatruc, band_edges_faw[i*2+1][:a] - deltatruc]
469
+ debug_plot_args << '-k'
470
+ end
471
+ debug_plot_args << Roctave.linspace(0, Math::PI, 1024)
472
+ debug_plot_args << debug_plot_args[-1].collect{|v| q.call(v)*p_w.call(v)}
473
+ debug_plot_args << '-g;First response;'
474
+
475
+ debug_plot_args << frequencies
476
+ debug_plot_args << resp_interpolate
477
+ debug_plot_args << '-r;New response;'
478
+
479
+ debug_plot_args << l_plus_two_extremal_frequencies
480
+ debug_plot_args << Roctave.interp1(frequencies, resp_interpolate, l_plus_two_extremal_frequencies)
481
+ debug_plot_args << 'pr;Extremals;'
482
+ Roctave.plot(*debug_plot_args, grid: true, xlim: [0, Math::PI], title: "Iteration #{i}")
483
+
484
+ error = (0 ... frequencies.length).collect do |i|
485
+ weights[i]*(amplitudes[i] - resp_interpolate[i])
486
+ end
487
+
488
+ max_error = error.collect{|r| r.abs - deltatruc.abs}.max
489
+ puts "Maximum |error - delta| = #{max_error}"
490
+ break if max_error < 0.001 or i > 10
491
+ end
492
+
493
+ raise "Failed to converge" if i > 10
494
+ ###
495
+
496
+ b
497
+ end
498
+ end
499
+