Java 中输出三角波形的公式问题
Problems with formula to output a triangle waveform in Java
我让我的 wave 文件创建器开始工作,我将它分成三个 classes,我还制作了一个正弦波发生器,它继承了一个名为 waveform 的抽象 class,我可以导出 8 和 16位单声道或立体声正弦波。我正在尝试制作一个名为 TriangleWave Generator 的 class 来输出三角波音调,但我无法使用第一个公式 https://en.wikipedia.org/wiki/Triangle_wave# 中的代数。它只会输出规定的最高谐波,不会将它们与基波混合在一起[=13=]
样本长度:以秒为单位的长度
点:个体样本
放大器限制:可能的最高位置
谐波:用于制作波形的谐波数 1 = 基波,2 = 第一泛音,3 = 第二泛音......
频率:基频(Middle C = 261.63)
采样率 = 44100; (CD 品质)
三角形样本数组:样本数据
这是我的代码
public class TriangleGenerator extends Waveform {
// constants
public static final int HARMONIC_COUNT = 16;
// instance variabls
int harmonics;
int[] triangleSample;
int addCount;
// constructor
public TriangleGenerator(double amplitude, double frequency, int bitRate, double duration, int harmonics) {
super(amplitude, frequency, bitRate, duration);
// sample data
triangleSample = new int[sampleLength];
calculateAmpLimit();
this.harmonics = harmonics;
}
// one arg cunstructor
public TriangleGenerator(double frequency) {
this(AMPLITUDE, frequency, BIT_RATE, DURATION, HARMONIC_COUNT);
}
// no args constructor
public TriangleGenerator() {
this(AMPLITUDE, FREQUENCY, BIT_RATE, DURATION, HARMONIC_COUNT);
}
@Override
public int[] generateWaveForm() {
// generate the actual waveform
for (int i = 0; i < sampleLength; i++) {
point = (int)(ampLimit * ((8 / Math.pow(Math.PI, 2)) * sumnate(harmonics - 1, Math.pow(-1, addCount))
* Math.pow(harmonics, -2) * Math.sin(2 * Math.PI * frequency * harmonics * i / SAMPLE_RATE)));
triangleSample[i] = point;
}
// return the sample data
return triangleSample;
}
public double sumnate(int n, double adder) {
double sum = 0;
for (addCount = 0; addCount <= n; addCount++) {
sum += adder;
}
return sum;
}
}
在triangle wave的公式中:
模式编号n
取决于谐波标签i
:
这意味着它还必须对组件求和
在当前的实现中不会发生这种情况。一种可能的实现是:
public int[] generateWaveForm() {
for (int t = 0; t < sampleLength; t++) {
triangleSample[t] = (int)(ampLimit * 8.0 / Math.pow(Math.PI, 2.0) * getDataPoint(t, N));
}
return triangleSample;
}
private double getDataPoint(int t, int N) {
double sum = 0;
for (int i = 0; i <= N - 1; i++) {
sum += getHarmonicShare(t, i);
}
return sum;
}
private double getHarmonicShare(int t, int i) {
double n = 2.0 * i + 1.0;
return Math.pow(-1.0, i) * Math.pow(n, -2.0) * Math.sin(2.0 * Math.PI * frequency * (t / SAMPLE_RATE) * n);
}
此处 t
、i
、n
和 N
对应于公式中的值。 frequency
表示频率。其余值对应于发布代码的参数。
曲线达到值sampleLength / SAMPLE_RATE
。周期为1 / frequency
,显示的帧中有(sampleLength / SAMPLE_RATE) * frequency
个周期。
示例:
sampleLength: 500
ampLimit: 100.00
SAMPLE_RATE: 44100.00
frequency: 261.63
sampleLength / SAMPLE_RATE: 0.0113378685
1 / frequency: 0.0038221916
(sampleLength / SAMPLE_RATE) * frequency: 2.9663265306
下面显示了使用 JFreeChart 的不同 N
的相应曲线:
您是否有理由要使用 sin 来执行此操作而不是直接通过线性公式生成直线?使用 sin 的一个优点是您不会因混叠而导致谐波失真,但如果这是一个问题,那么您可以进行过采样。问题是 sin 比基本算术慢得多。
我让我的 wave 文件创建器开始工作,我将它分成三个 classes,我还制作了一个正弦波发生器,它继承了一个名为 waveform 的抽象 class,我可以导出 8 和 16位单声道或立体声正弦波。我正在尝试制作一个名为 TriangleWave Generator 的 class 来输出三角波音调,但我无法使用第一个公式 https://en.wikipedia.org/wiki/Triangle_wave# 中的代数。它只会输出规定的最高谐波,不会将它们与基波混合在一起[=13=]
样本长度:以秒为单位的长度 点:个体样本 放大器限制:可能的最高位置 谐波:用于制作波形的谐波数 1 = 基波,2 = 第一泛音,3 = 第二泛音...... 频率:基频(Middle C = 261.63) 采样率 = 44100; (CD 品质) 三角形样本数组:样本数据
这是我的代码
public class TriangleGenerator extends Waveform {
// constants
public static final int HARMONIC_COUNT = 16;
// instance variabls
int harmonics;
int[] triangleSample;
int addCount;
// constructor
public TriangleGenerator(double amplitude, double frequency, int bitRate, double duration, int harmonics) {
super(amplitude, frequency, bitRate, duration);
// sample data
triangleSample = new int[sampleLength];
calculateAmpLimit();
this.harmonics = harmonics;
}
// one arg cunstructor
public TriangleGenerator(double frequency) {
this(AMPLITUDE, frequency, BIT_RATE, DURATION, HARMONIC_COUNT);
}
// no args constructor
public TriangleGenerator() {
this(AMPLITUDE, FREQUENCY, BIT_RATE, DURATION, HARMONIC_COUNT);
}
@Override
public int[] generateWaveForm() {
// generate the actual waveform
for (int i = 0; i < sampleLength; i++) {
point = (int)(ampLimit * ((8 / Math.pow(Math.PI, 2)) * sumnate(harmonics - 1, Math.pow(-1, addCount))
* Math.pow(harmonics, -2) * Math.sin(2 * Math.PI * frequency * harmonics * i / SAMPLE_RATE)));
triangleSample[i] = point;
}
// return the sample data
return triangleSample;
}
public double sumnate(int n, double adder) {
double sum = 0;
for (addCount = 0; addCount <= n; addCount++) {
sum += adder;
}
return sum;
}
}
在triangle wave的公式中:
模式编号n
取决于谐波标签i
:
这意味着它还必须对组件求和
在当前的实现中不会发生这种情况。一种可能的实现是:
public int[] generateWaveForm() {
for (int t = 0; t < sampleLength; t++) {
triangleSample[t] = (int)(ampLimit * 8.0 / Math.pow(Math.PI, 2.0) * getDataPoint(t, N));
}
return triangleSample;
}
private double getDataPoint(int t, int N) {
double sum = 0;
for (int i = 0; i <= N - 1; i++) {
sum += getHarmonicShare(t, i);
}
return sum;
}
private double getHarmonicShare(int t, int i) {
double n = 2.0 * i + 1.0;
return Math.pow(-1.0, i) * Math.pow(n, -2.0) * Math.sin(2.0 * Math.PI * frequency * (t / SAMPLE_RATE) * n);
}
此处 t
、i
、n
和 N
对应于公式中的值。 frequency
表示频率。其余值对应于发布代码的参数。
曲线达到值sampleLength / SAMPLE_RATE
。周期为1 / frequency
,显示的帧中有(sampleLength / SAMPLE_RATE) * frequency
个周期。
示例:
sampleLength: 500
ampLimit: 100.00
SAMPLE_RATE: 44100.00
frequency: 261.63
sampleLength / SAMPLE_RATE: 0.0113378685
1 / frequency: 0.0038221916
(sampleLength / SAMPLE_RATE) * frequency: 2.9663265306
下面显示了使用 JFreeChart 的不同 N
的相应曲线:
您是否有理由要使用 sin 来执行此操作而不是直接通过线性公式生成直线?使用 sin 的一个优点是您不会因混叠而导致谐波失真,但如果这是一个问题,那么您可以进行过采样。问题是 sin 比基本算术慢得多。