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.
- checksums.yaml +7 -0
- data/LICENSE +674 -0
- data/README.md +33 -0
- data/ext/roctave/cu8_file_reader.c +331 -0
- data/ext/roctave/cu8_file_reader.h +30 -0
- data/ext/roctave/extconf.rb +6 -0
- data/ext/roctave/fir_filter.c +795 -0
- data/ext/roctave/fir_filter.h +29 -0
- data/ext/roctave/freq_shifter.c +410 -0
- data/ext/roctave/freq_shifter.h +29 -0
- data/ext/roctave/iir_filter.c +462 -0
- data/ext/roctave/iir_filter.h +29 -0
- data/ext/roctave/roctave.c +38 -0
- data/ext/roctave/roctave.h +27 -0
- data/lib/roctave.rb +168 -0
- data/lib/roctave/bilinear.rb +92 -0
- data/lib/roctave/butter.rb +87 -0
- data/lib/roctave/cheby.rb +180 -0
- data/lib/roctave/cu8_file_reader.rb +45 -0
- data/lib/roctave/dft.rb +280 -0
- data/lib/roctave/filter.rb +64 -0
- data/lib/roctave/finite_difference_coefficients.rb +73 -0
- data/lib/roctave/fir.rb +121 -0
- data/lib/roctave/fir1.rb +134 -0
- data/lib/roctave/fir2.rb +246 -0
- data/lib/roctave/fir_design.rb +311 -0
- data/lib/roctave/firls.rb +380 -0
- data/lib/roctave/firpm.rb +499 -0
- data/lib/roctave/freq_shifter.rb +47 -0
- data/lib/roctave/freqz.rb +233 -0
- data/lib/roctave/iir.rb +80 -0
- data/lib/roctave/interp1.rb +78 -0
- data/lib/roctave/plot.rb +748 -0
- data/lib/roctave/poly.rb +46 -0
- data/lib/roctave/roots.rb +73 -0
- data/lib/roctave/sftrans.rb +157 -0
- data/lib/roctave/version.rb +3 -0
- data/lib/roctave/window.rb +116 -0
- data/roctave.gemspec +79 -0
- data/samples/butter.rb +12 -0
- data/samples/cheby.rb +28 -0
- data/samples/dft.rb +18 -0
- data/samples/differentiator.rb +48 -0
- data/samples/differentiator_frequency_scaling.rb +52 -0
- data/samples/fft.rb +40 -0
- data/samples/finite_difference_coefficient.rb +53 -0
- data/samples/fir1.rb +13 -0
- data/samples/fir2.rb +14 -0
- data/samples/fir2_windows.rb +29 -0
- data/samples/fir2bank.rb +30 -0
- data/samples/fir_low_pass.rb +44 -0
- data/samples/firls.rb +77 -0
- data/samples/firpm.rb +78 -0
- data/samples/hilbert_transformer.rb +20 -0
- data/samples/hilbert_transformer_frequency_scaling.rb +47 -0
- data/samples/plot.rb +45 -0
- data/samples/stem.rb +8 -0
- data/samples/type1.rb +25 -0
- data/samples/type3.rb +24 -0
- data/samples/windows.rb +25 -0
- 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
|
+
|