Документ взят из кэша поисковой машины. Адрес оригинального документа : http://www.naic.edu/~phil/hardware/pdev/fpga/gx/jfft/src/mkcoeff
Дата изменения: Thu Jun 26 04:28:48 2008
Дата индексирования: Sat Sep 6 19:57:59 2008
Кодировка:

Поисковые слова: п п п п п п п п п п
#!/usr/bin/perl

#
# Jeff Mock
# 2030 Gough
# San Francisco, CA 94109
# jeff@mock.com
# (c) 2004
#

#
# $URL: https://www.mock.com/svn/pdev/trunk/gx/jfft/src/mkcoeff $
# $Id: mkcoeff 593 2006-10-13 03:29:28Z jeff $
#

use Getopt::Long;
use Math::Trig;
use Math::BigInt;
use POSIX;

# Window types
%windows = (
'none' => 1,
'rect' => 1,
'hamming' => 1,
'hanning' => 1,
'blackman' => 1,
'bartlett' => 1,
'tri' => 1,
'fft' => 1,
);


$opt_width = 18; # datapath width
$opt_n = 32; # length of fft
$opt_start = 2;
$opt_stop = 1;
$opt_fwid = 4;
$opt_window = "none";
$opt_narrow = 1.00;
$opt_unity = 0;
$opt_maxlen = 8192;
$opt_fn = "coeff.out";
$opt_bin = 0;

%opts = (
'width=o' => \$opt_width,
'n=o' => \$opt_n,
'start=f' => \$opt_start,
'stop=f' => \$opt_stop,
'fwid=o' => \$opt_fwid,
'window=s' => \$opt_window,
'narrow=f' => \$opt_narrow,
'unity' => \$opt_unity,
'maxlen=o' => \$opt_maxlen,
'fn=s' => \$opt_fn,
'bin' => \$opt_bin,
);

if (!GetOptions(%opts)) {
my $wins = join ' ', keys %windows;
print STDERR "
Make coefficient table for FIR filter section of PFB

mkcoeff [options]
[--n=n] Length of FFT ($opt_n)
[--width=n] Datapath width of FFT ($opt_width)
[--start=f] Start postion (x pi) in sinc
[--stop=f] Stop position (x pi) in sinc
[--fwid=n] Total width of filter (x pi)
[--window=s] Windowing function:
${wins}
[--narrow=f] Compress sync function ($opt_narrow)
[--unity] Unity gain filter coefficients
[--maxlen] Maximum length of variable len transform
[--fn=s] Filename for coefficient table
[--bin] Out coefficients as binary data (16-bit only)

\n";
exit 1;
}

die "Window type ${opt_window} not defined"
unless $windows{$opt_window};

die "maxlen ${opt_maxlen} must be longer than n ${opt_n}"
unless $opt_maxlen >= $opt_n;

$g_gain = 0.0;

sub pfb_coeff_vals {
my $start = shift;
my $stop = shift;
my $width = shift;
my $n = shift;
my $fwid = shift;

my @vals = ();
my @cmts = ();
my $highbit = 1 << ($width-1);
my $mask = (1 << $width) - 1;

if ($opt_window eq "fft") {
# This is a dummy for testing that puts 1's in
# the last coefficient rom and 0's in the other ROMs
# for a unity transfer function from the filter. Output
# of the PFB should look just like an FFT.
#
if ($start == $fwid/2) {
# 1's
for my $idx (0 .. $n-1) {
my $hex = ($highbit-1) & $mask;
my $cmt = "1";
push @vals, Math::BigInt->new($hex);
push @cmts, $cmt;
}
} else {
# 0's
for my $idx (0 .. $n-1) {
my $hex = 0;
my $cmt = "0";
push @vals, Math::BigInt->new($hex);
push @cmts, $cmt;
}
}
} else {
# Generate floating vals for portion of sin(x)/x
# for my $idx (0 .. $n-1) {
# my $t = $start + ($stop-$start)*$idx/$n;

# Make values for entire window, not just this
# coefficient ROM.
#
for my $idx (0 .. $n*$opt_fwid-1) {
my $t = $opt_fwid/2 - $idx/$n;

my $v = 1.0;
$v = 1.0 * $opt_narrow * sin($t * pi / $opt_narrow) / ($t * pi)
if ($t != 0);
my $cmt = sprintf("sinc(%.3f * pi / %.3f )", $t, $opt_narrow);
push @vals, $v;
push @cmts, $cmt;
}
if ($opt_window eq "tri" || $opt_window eq "bartlett") {
# Triangle windowing function
for my $idx (0 .. $n*$opt_fwid-1) {
# my $t = $start + ($stop-$start)*$idx/$n;
my $t = $opt_fwid/2 - $idx/$n;
my $m = 1.0 - abs($t / ($opt_fwid/2));
$vals[$idx] *= $m;
$cmts[$idx] = sprintf("%s * %.3f = %.3f", $cmts[$idx],
$m, $vals[$idx]);
}
} elsif ($opt_window eq "hanning") {
# Triangle windowing function
for my $idx (0 .. $n*$opt_fwid-1) {
# my $t = $start + ($stop-$start)*$idx/$n;
my $t = $opt_fwid/2 - $idx/$n;
my $m = abs($t / ($opt_fwid/2)) * pi;
$m = 0.5 + 0.5*cos($m);
$vals[$idx] *= $m;
$cmts[$idx] = sprintf("%s * %.3f = %.3f", $cmts[$idx],
$m, $vals[$idx]);
}
} elsif ($opt_window eq "hamming") {
# Triangle windowing function
for my $idx (0 .. $n*$opt_fwid-1) {
# my $t = $start + ($stop-$start)*$idx/$n;
my $t = $opt_fwid/2 - $idx/$n;
my $m = abs($t / ($opt_fwid/2)) * pi;
$m = 0.54 + 0.46*cos($m);
$vals[$idx] *= $m;
$cmts[$idx] = sprintf("%s * %.3f = %.3f", $cmts[$idx],
$m, $vals[$idx]);
}
} elsif ($opt_window eq "blackman") {
# Triangle windowing function
for my $idx (0 .. $n*$opt_fwid-1) {
# my $t = $start + ($stop-$start)*$idx/$n;
my $t = $opt_fwid/2 - $idx/$n;
my $m = abs($t / ($opt_fwid/2)) * pi;
$m = 0.42 + 0.5*cos($m) + 0.08*cos(2.0*$m);
$vals[$idx] *= $m;
$cmts[$idx] = sprintf("%s * %.3f = %.3f", $cmts[$idx],
$m, $vals[$idx]);
}
} elsif ($opt_window eq "none" || $opt_window eq "rect") {
# Just fixup comments...
for my $idx (0 .. $n*$opt_fwid-1) {
my $cmt = sprintf("%s = %.4f", $cmts[$idx], $vals[$idx]);
$cmts[$idx] = $cmt;
}
} else {
die "Botch: failed to handle window type ${opt_window}";
}

# Calculate peak filter value and DC gain
my $peak = 0.0;
my $gain = 0.0;
my $gain_tot = 0;
my $gain_min = 10.0;
my $gain_max = 0.0;
my $gain_sum = 0.0;
my $peak_sum = 0.0;
for my $pos (0 .. $n-1) {
$gain_sum = 0.0;
$peak_sum = 0.0;
for ($i=0; $i<$opt_fwid*$n; $i+=$n) {
$gain_sum += $vals[$i+$pos];
$peak_sum += abs($vals[$i+$pos]);
}
$peak = $peak_sum if $peak_sum>$peak;
$gain_max = $gain_sum if $gain_sum>$gain_max;
$gain_min = $gain_sum if $gain_sum<$gain_min;
$gain_tot += $gain_sum;
}
$gain = $gain_tot / $n;

# printf " gain min %.3f\n", $gain_min;
# printf " gain max %.3f\n", $gain_max;
# printf " gain %.3f\n", $gain;
# printf " peak %.3f\n", $peak;


# Scale values for unity peak gain
if ($opt_unity) {
$_ /= $gain for (@vals);
printf " DC gain scaled to 1.0, peak gain of %.3f\n",
$peak/$gain;
$g_gain = sprintf("%.3f", $peak/$gain);
} else {
$_ /= $peak for (@vals);
printf " DC gain scaled by %.3f for peak gain of 1.0\n",
1.0/$peak;
$g_gain = sprintf("%.3f", $gain/$peak);
}



$si = ($opt_fwid/2 - $opt_start)*$opt_n;
@vals = @vals[$si..$si+$n-1];
@cmts = @cmts[$si..$si+$n-1];

# Convert floating vals to hex BigInt of appropriate width
for my $idx (0 .. $n-1) {
my $hex = int(($vals[$idx]*$highbit) + 0.5);
$hex = ($highbit-1) if $hex >= $highbit;
$hex = $hex & $mask;
$vals[$idx] = Math::BigInt->new($hex);
}
}
return (\@vals, \@cmts);
}

($vals,$cmts) = pfb_coeff_vals($opt_start, $opt_stop, $opt_width,
$opt_n, $opt_fwid);

if ($opt_bin) {
die "output width ($opt_width) must be 16 for binary mode" unless
$opt_width==16;
open FD, "> $opt_fn";
binmode(FD);
for ( 1 .. $opt_maxlen / $opt_n ) {
for ( @$vals ) {
my $v = $_->numify();
my $s = pack 'n', $v;
print FD $s;
}
}
close FD;
} else {
open FD, "> $opt_fn";
for ( 1 .. $opt_maxlen / $opt_n ) {
for ( @$vals) {
printf FD "%08x\n", $_->numify();
}
}
close FD;
}