roctave 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|