安卓java使用FFT算法将pcm录音文件中的数据处理并生成Bitmap并用Glide将其显示到安卓控件ImageView中
本人CSDN新手,第一次发帖,如有不当之处还望指出。
1.首先需要实例化两个数组对象,以便将pcm录音文件中的数据存储起来:
在MainActivity中:
代码如下:
private byte[] buffer=new byte[bufferSizeLnBytes];
private short[] buffer1=new short[bufferSizeLnBytes*2];//恢复原来的,再变为原来的2
2.然后需要创建一个Buttom控件以便实现点击触发相应函数及操作,这里的Stop按钮的ID为mainButton3,以及用于显示生成的频谱特性Bitmap图所用的ImageView,创建它,其ID为:mainImageView1
其它控件可不管
相应的main.xml中的配置如下:
3.下面实例化Button对象,使用findViewById方法,定义Stop按钮相应的触发事件,触发事件包括读取recording.pcm录音文件并将数据储存在数组并写入AudioTrack进行播放,更主要的是将数据储存在buffer1数组中,并调用Complexmatrix中的FFT方法进行频谱分析,并将结果生成Bitmap,再用Glide加载Bitmap并显示到ImgeView中
下面实现代码如下:
final ImageView img1=findViewById(R.id.mainImageView1);
final Complexmatrix complexmatrix=new Complexmatrix();
Button bt3=findViewById(R.id.mainButton3);
bt3.findViewById(R.id.mainButton3);
bt3.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View p1)
{
//audiorecord1.stop();
boolean mIsPlaying=true;
int bufferSize=AudioTrack.getMinBufferSize(44100,AudioFormat.CHANNEL_CONFIGURATION_STEREO,AudioFormat.ENCODING_PCM_16BIT);
short[] buffer=new short[bufferSize];
File pcm1=new File(Environment.getExternalStorageDirectory().getAbsolutePath()+"/recording.pcm");
try
{
//定义输入流,将音频写入到AudioTrack类中,实现播放
DataInputStream dis=new DataInputStream(new BufferedInputStream(new FileInputStream(pcm1)));
//实例AudioTrack
AudioTrack track=new AudioTrack(AudioManager.STREAM_MUSIC,44100,AudioFormat.CHANNEL_CONFIGURATION_STEREO,AudioFormat.ENCODING_PCM_16BIT,bufferSize,AudioTrack.MODE_STREAM);
//开始播放
track.play();
//由于AudioTrack播放的是流,所以,我们需要一边播放,一边读取
try
{
while (mIsPlaying && dis.available() > 0)
{
int i=0;
while(dis.available()>0&&i<buffer.length){
buffer[i]=dis.readShort();
// buffer1[i]=buffer[i];//增加数据为原来2倍
buffer1[2*i]=buffer[i];
buffer1[2*i+1]=buffer[i];
i++;
}
//然后将数据写入到AudioTrack中
track.write(buffer,0,buffer.length);
}
//播放结束
track.stop();
dis.close();
}
catch (IOException e)
{}
}
catch (FileNotFoundException e)
{}
short[] s=buffer1;//这里将储存的数据附在s中
Bitmap bmp1=complexmatrix.FFT(s.length,44100,s,MainActivity.this);//该方法没有用到FFT中的类似F8与F4,F64与F32中的关系,处理数据较慢
//Bitmap bmp1=complexmatrix.getanglewithFFT(s.length,44100,s,MainActivity.this);//该方法为FFT的核心方法,像这种方法用汇编语言写出来是最好的,作者水平有限,用java根据其原理写出该方法,速度还是比较快
ByteArrayOutputStream baos1=new ByteArrayOutputStream();
bmp1.compress(Bitmap.CompressFormat.JPEG,100,baos1);
byte[] bytes1=baos1.toByteArray();
Glide.with(MainActivity.this).load(bytes1).placeholder(R.drawable.ic_launcher).error(R.drawable.ic_launcher).into(img1);//Glide加载Bitmap方法,这里的Bitmao即为相应的频谱图
// TODO: Implement this method
}
});
4.接下来看看用到的类:
其中的复数类引用博客:
https://blog.csdn.net/ffj0721/article/details/78521821?utm_source=app
自己写的Complexmatrix复数矩阵类如下代码:
package com.mycompany.myndkapp2;
import android.content.*;
import android.widget.*;
import android.graphics.*;
import android.renderscript.*;
import java.util.*;
public class Complexmatrix
{
//public Complexmatrix(){};
public native byte[] bitbyte(double[] angle,double[] range,double[] axis);
public void newmatrix(int row1,int col1,double[] realmatrix1,double[] imagmatrix1){//改函数中row1,col1可以为2048但不能为4096及更大
this.row=row1;
this.col=col1;
this.realmatrix=new double[row1*col1];
for(int i=0;i<row1;i++){
for(int i1=0;i1<col1;i1++){
this.realmatrix[i*col1+i1]=realmatrix1[i*col1+i1];
}
}
this.imagmatrix=new double[row1*col1];
for(int i2=0;i2<row1;i2++){
for(int i3=0;i3<col1;i3++){
this.imagmatrix[i2*col1+i3]=imagmatrix1[i2*col1+i3];
}
}
}
public Complex get(int row,int col){
int index0=(row-1)*this.col+col-1;
//int index1=0;
///double a=this.realmatrix[1];
double re1=this.realmatrix[index0];
double im1=this.imagmatrix[(row-1)*this.col+col-1];
Complex rtn=new Complex(re1,im1);
/*
if(index0==index1){
rtn= new Complex(index0,index0);}
*/
//可以把Context传递进来使用Toast进行检验
//Toast.makeText(context,String.valueOf(index0),Toast.LENGTH_LONG).show();
return rtn;
}
public void set(int row,int col,Complex complexnum){
realmatrix[row*this.col+col]=complexnum.re();
//complexnum.re();
imagmatrix[row*this.col+col]=complexnum.im();
}
public boolean AtimesB(Complexmatrix complexmatrixB){
if(this.col==complexmatrixB.getrow()){
//this.col=complexmatrixB.getcol();一开始不能改变本地矩阵的列数
double[] newrealmatrix=new double[this.row*complexmatrixB.getcol()];
double[] newimagmatrix=new double[this.row*complexmatrixB.getcol()];
for(int i=0;i<this.row;i++){
for(int j=0;j<complexmatrixB.getcol();j++){
double im2=0;
double re2=0;
Complex complex0=new Complex(0,0);
for(int j1=0;j1<this.getcol();j1++){
// Complex complex2=complex0;
Complex complex1=this.get(i+1,j1+1).times(complexmatrixB.get(j1+1,j+1));
complex0=complex0.plus(complex1);
}
// this.set(i,j,complex0);
im2=complex0.im();
re2=complex0.re();
newrealmatrix[i*complexmatrixB.getcol()+j]=re2;
newimagmatrix[i*complexmatrixB.getcol()+j]=im2;
}
}
this.newmatrix(this.row,complexmatrixB.getcol(),newrealmatrix,newimagmatrix);
return true;
}else{
return false;
}
}
public void transpose(){
double[] realmatrix2=new double[this.col*this.row];
double[] imgamatrix2=new double[this.col*this.row];
for(int i=0;i<this.row;i++){
for(int j=0;j<this.col;j++){
//double realexchangenum=0;
//double imgaexchangenum=0;
//this.realmatrix[i*this.col+j];
//realexchangenum=this.realmatrix[i*this.col+j];
//this.realmatrix[i*this.getcol()+j]=this.realmatrix[j*
//double[] realmatrix2=new double[this.getcol()*this.getrow()];将实例化对象函数放for循环外面
realmatrix2[j*this.row+i]=this.realmatrix[i*this.col+j];
//double[] imgamatrix2=new double[this.getcol()*this.getrow()];
imgamatrix2[j*this.row+i]=this.imagmatrix[i*this.col+j];
//Complexmatrix matrix2=new Complexmatrix();
//this.newmatrix(this.getcol(),this.getrow(),realmatrix2,imgamatrix2);放在两个for循环外面
}
}
//this.realmatrix=new double[this.row*this.col];
/*
int row=this.row;
int col=this.col;
double[] matrixp1=new double[2*2];
double[] matrixp2=new double[2*2];
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
matrixp1[i*2+j]=1;
matrixp2[i*2+j]=2;
}
}
this.newmatrix(2,2,matrixp1,matrixp2);
*/
this.newmatrix(col,row,this.realmatrix,this.imagmatrix);//这里反映问题是之前AtimesB后列数没更正,不用更正突然没问题了
//最后发现是MainActivity中的一个Toast中获取了改矩阵的2行一列的元素,实际转置后是没有该元素的
//Toast.makeText(context,String.valueOf(col)+"---"+String.valueOf(row),Toast.LENGTH_LONG).show();
}
public void conjugate(){
//for(int i=0;i<this.col
for(int i=0;i<this.getcol();i++){
}
for(int i=0;i<this.getrow();i++){
for(int j=0;j<this.getcol();j++){
this.imagmatrix[i*this.col+j]=-this.imagmatrix[i*this.col+j];
}
}
}
public void Hermition(){
this.transpose();
this.conjugate();
}
public int getrow(){
return this.row;
}
public int getcol(){
return this.col;
}
private static final int WIDTH = 320;
private static final int HEIGHT = 240;
private static final int STRIDE =320; // must be >= WIDTH
private Bitmap[] mBitmaps;
private int[] mColors;
private static int[] createColors() {
int[] colors = new int[STRIDE * HEIGHT];
for (int y = 0; y < HEIGHT; y++) {
for (int x = 0; x < WIDTH; x++) {
int r = x * 255 / (WIDTH - 1);
int g = y * 255 / (HEIGHT - 1);
int b = 255 - Math.min(r, g);
int a = Math.max(r, g);
colors[y * STRIDE + x] = (a << 24) | (r << 16) | (g << 8) | b;
}
}
return colors;
}
public Bitmap FFT(int n,double Ws,short[] s,Context context){//将Byte[] s改成short[] s
//没有使用FFT的情况,将会直接闪退,并不会闪退,只不过计算会比较慢
//由wb*n=ws,可得wb=ws/n
//方法已被修正,现在正确
//n=1024时,计算需花费时间1273毫秒
//n=2048时,计算需花费时间4883毫秒
//目前适用n最大为2048
int currentTimeMillis=(int)System.currentTimeMillis();
Ws为采样频率,mp3为44100,Wb为基频,是原采样数据频率的最小值,其它频率为该频率的n倍,n=0,1,2...n-1,最后生成的结果一般去前半部分,是由于人耳听觉感知的频率范围为20-20000Hz,而结果中含有0-(n-1)/n*Ws的频率成分
n=1024;
double Wb=Ws/n;
double[] Wn=new double[n];
for(int i0=0;i0<n;i0++){
Wn[i0]=i0*Wb;
}
//下面组成FFT中的矩阵Fn,第一行为基频率的0倍,每一行的频率为该行的(行数-1)倍的基频
double[] realmatrix1=new double[n*n];
double[] imgamatrix1=new double[n*n];
for(int i7=0;i7<n;i7++){
//Complex w1=new Complex(0,Wn[i7]);//先不实际化复数对象
//先把该行的频率附值给一个double变量
double w2=Wn[i7];
for(int j7=0;j7<n;j7++){
//再把频率值根据列数翻倍,并且要乘以2*Math.PI(),错了,是2*Math.2PI/Ws
double w3=w2*j7*2*Math.PI/Ws;
//最后再取关于e的指数,并且实例化一个复数对象
Complex w4=new Complex(0,w3);
Complex w5=w4.exp();
//要将最后得到的复数附在复数矩阵对应的位置上
realmatrix1[i7*n+j7]=w5.re();
imgamatrix1[i7*n+j7]=w5.im();
}
}
Complexmatrix Fn=new Complexmatrix();
//Fn取共轭
//Fn.conjugate();Fn应该先生成再取共轭
Fn.newmatrix(n,n,realmatrix1,imgamatrix1);//n=4096时这里导致闪退
Fn.conjugate();
//en是Fn右乘的采样数据列向量矩阵
//realmat
double[] realmatrix2=new double[n*1];
double[] imgamatrix2=new double[n*1];
//for(//虚部为零的矩阵
for(int i3=0;i3<n;i3++){
for(int j3=0;j3<1;j3++){
imgamatrix2[i3*1+j3]=0;
}
}
//实部为采样数据的列向量矩阵
for(int i4=0;i4<n;i4++){
for(int j4=0;j4<1;j4++){
//realmatrix2[i4*1+j4]=s[i4*1+j4];
realmatrix2[i4*1+j4]=(double)s[i4*1+j4]/65536;//256*256=65536
}
}
Complexmatrix enmatrix=new Complexmatrix();
enmatrix.newmatrix(n,1,realmatrix2,imgamatrix2);//左边代码之前不存在导致后面出错
//enmatrix.AtimesB(Fn);//左乘矩阵的列数与右乘矩阵行数不匹配
String text="";
//var s = str1.concat(str2);//使用concat时需要将结果赋给一个变量
//text.concat("test");
Fn.AtimesB(enmatrix);//Fn*en,Fn是FFT中的n阶傅里叶矩阵,en是pcm录音文件中的n个采样数据
int costtime1=(int)System.currentTimeMillis()-currentTimeMillis;
Toast.makeText(context,String.valueOf(costtime1),Toast.LENGTH_LONG).show();
//将复数的模和主值存储起来
double[] length=new double[n];
double[] angle=new double[n];
for(int i5=0;i5<n;i5++){
for(int j5=0;j5<1;j5++){
//Fn.get(i5*1+j5+1,1).re()*Fn.get(i5*1+j5
length[i5]=Math.sqrt(Fn.get(i5*1+j5+1,1).re()*Fn.get(i5*1+j5+1,1).re()+Fn.get(i5*1+j5+1,1).im()*Fn.get(i5*1+j5+1,1).im());//再开方得到复数的模
if(Fn.get(i5*1+j5+1,1).re()!=0){
// angle[i5]=Math.atan(Fn.get(i5+1,1).im()/Fn.get(i5+1,j5).re());//得到复数的主值,考虑实部和虚部正负性
try{
if(Fn.get(i5*1+j5,1).re()>0){
//angle[i5]=Math.atan(Fn.get(i5*1+j5)
angle[i5]=Math.atan(Fn.get(i5*1+j5,1).im()/Fn.get(i5*1+j5,1).re());
}else{
if(Fn.get(i5*1+j5,1).im()>=0){
angle[i5]=Math.atan(Fn.get(i5*1+j5,1).im()/Fn.get(i5*1+j5,1).re())+Math.PI;
}else{
angle[i5]=Math.atan(Fn.get(i5*1+j5,1).im()/Fn.get(i5*1+j5,1).re())-Math.PI;
}
}
}catch(Exception e){}
}else{
if(Fn.get(i5*1+j5+1,1).im()>0){
angle[i5]=Math.PI/2;
}else{
if(Fn.get(i5*1+j5+1,1).im()<0){
angle[i5]=Math.PI*(-1)*0.5;
}else{
angle[i5]=0;
}
}
}
}
}
double[] range=new double[n];//range是幅度
for(int i6=0;i6<n;i6++){
for(int j6=0;j6<1;j6++){
range[i6*1+j6]=20*Math.log10(length[i6*1+j6]);
}
}
//得到的range为幅度,angle为角度
//将幅度和角度与频率的关系画成Bode图得出频谱分析图
double[] axis=new double[n];
for(int i=0;i<n;i++){
axis[i]=i*Wb;
}
//byte[] bitebyte1=bitbyte(angle,range,axis);左边这行代码不能用
byte[] bitebyte1=new byte[320*240*4];
for(int i2=0;i2<240;i2++){
int height=(int)(180-(angle[i2]*180/Math.PI+180)*0.5+30);//转换成弧度制
//int height=(int)(180-(range[i2]+180)*0.5+30);//幅频特性Bode图,单位为分贝db
//int height=(int)(180-(length[i2]+180)*0.5+30);//复数求模所得的幅频图,取对数并乘以20后得到以分贝为单位的幅频特性Bode图
int width=(int)(40+i2);
for(int j2=0;j2<320;j2++){
for(int k2=0;k2<4;k2++){
if(height>=0&&height<120){
for(int i4=0;i4<120-height;i4++){
switch(k2){
case 0:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-1;//-1的补码为11111111
}break;
case 1:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-18;//-18的补码为0xee;
}break;
case 2:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-18;
}break;
case 3:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-1;
}break;
}
}
}else{
if(height>=120&&height<210){
for(int i4=0;i4<height-120;i4++){
switch(k2){
case 0:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-1;//-1的补码为11111111
}break;
case 1:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-18;//-18的补码为0xee;
}break;
case 2:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-18;
}break;
case 3:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-1;
}break;
}}}
}
}
}
}
Bitmap bmp0=Bitmap.createBitmap(320,240,Bitmap.Config.ARGB_8888);
int[] bmpint=new int[240*320];
for(int i=0;i<240*320;i++){
for(int j=0;j<4;j++){
// bmpint[i]=bitebyte1[i*4+j];
try{
switch(j){
case 0:{
bmpint[i]=bitebyte1[i*4+j]&0xff;
//bmpint[i]=0xffffee00;
}break;
case 1:{
bmpint[i]+=(bitebyte1[i*4+j]&0xff)<<8;
}break;
case 2:{
bmpint[i]+=(bitebyte1[i*4+j]&0xff)<<16;
}break;
case 3:{
bmpint[i]+=(0xff&0xff)<<24;//int型产量左移一定位数,并实现byte[4]转int型
}break;
}
}catch(Exception e){
}
}
}
//bmp0.setp
bmp0.setPixels(bmpint,0,320,0,0,320,240);
//Toast.makeText(context,String.valueOf(Integer.compare(5,3)),Toast.LENGTH_LONG).show();Integer.compare(5,3)返回1,Integer.compare(1,2)返回-1
//Bitmap bmp1=BitmapFactory.decodeByteArray(bitebyte1,0,240*320*4);
Bitmap bmp1=null;//检查问题,已排除问题,然而并没有
return bmp0;
//return null;
}
public Bitmap getanglewithFFT(int n,double Ws,short[] s,Context context){//查错
//没有使用FFT的情况,将会直接闪退,并不会闪退,只不过计算会比较慢
//使用FFT后速度明显加快,但是发现和没使用FFT的情况处理后数据不同
//由wb*n=ws,可得wb=ws/n
//方法已被修正,现在正确
//n=1024时计算数据花费时间359毫秒
//n=2048时计算数据话费时间343毫秒
//n=4096时计算数据花费时间400毫秒
//目前适用n最大为2048,最大为4096
int currentTimeMillis=(int)System.currentTimeMillis();
n=1024;
double Wb=Ws/n;
double[] Wn=new double[n];
for(int i0=0;i0<n;i0++){
Wn[i0]=i0*Wb;
}
int m=(int)(Math.log(n)/Math.log(2));
short[][] P=new short[1][n];
Complexmatrix Fn=new Complexmatrix();
//Toast.makeText(context,String.valueOf(m),Toast.LENGTH_LONG).show();
for(int i=0;i<m;i++){
/*
if(i== 0){
}
short[] P1=new short[m/2];
short[] P2=new short[m/2];*/
//short[][] P=new short[(int)Math.pow(2,i+1)][n/(int)Math.pow(2,i+1)];
int groupnum0=(int)Math.pow(2,i);
/*
if(i==0){
for(int i5=0;i5<2;i5++){
for(int i4=0;i4<m/2;i4++){
switch(i5){
case 0:{
P[0][i5*4+i4]=s[2*i4];
}break;
case 1:{
P[0][i5*4+i4]=s[2*i4+1];
}break;
}
}}
}
*/
//数据赋给P
if(i==0){
for(int i7=0;i7<n;i7++){
P[0][i7]=(short)(s[i7]);//要除以65536,不用除以65536
}
}
//奇偶分配可能有错,觉得没错,但是程序会闪退,解决了
int groupchild0=n/(2*groupnum0);//8/2=4,8/4=2
short[][] P3=new short[2*groupnum0][groupchild0];//[2][4],[4][2]
for(int i1=0;i1<2*groupnum0;i1++){//groupnum0改为2*groupnum0,然后出错,i1<2,i<4
int i0=(int)(0.5-0.5*Math.pow(-1,i1));
for(int i2=0;i2<groupchild0;i2++){
// P3[i1][i2]=P[i1%2][2*i2+i0];//i1%2是什么,是取余数
P3[i1][i2]=P[(int)(i1/2)][2*i2+i0];
// P3[i1][i2]=1;
}
}
P=P3;
}
//WFn
double[] realmatrix2=new double[n];
double[] imgamatrix2=new double[n];
for(int i3=0;i3<n;i3++){
realmatrix2[i3]=P[i3][0]/65536;//要除以65536
imgamatrix2[i3]=0;
}
Complexmatrix Pmatrix=new Complexmatrix();
Pmatrix.newmatrix(n,1,realmatrix2,imgamatrix2);
Pmatrix.conjugate();
Complexmatrix[] Fnconjugate0;
Complexmatrix[] Fnenconjugate=new Complexmatrix[n];
for(int i4=0;i4<m;i4++){
Complexmatrix Dmatrix=new Complexmatrix();//实例化FFT中矩阵D
// int row1=i4+1;该行有错
int row1=(int)Math.pow(2,i4);
double re1=0;
double im1=2*Math.PI/(2*row1);//这里是对的
// Complex WFn=new Complex(0,2*Math.PI/(2*row1));
Complex WFn;
/*
double[] realmatrix3=new double[row1];
double[] imgamatrix3=new double[row1];
*/
//Dmatrix有问题,解决了
double[] realmatrix3=new double[row1*row1];
double[] imgamatrix3=new double[row1*row1];
for(int i5=0;i5<row1;i5++){
for(int i6=0;i6<row1;i6++){
if(i5==i6){
WFn=new Complex(re1,i5*im1);
//WFn.exp();//要赋给一个复数,这是一个关键错误
WFn=WFn.exp();
realmatrix3[i5*row1+i6]=WFn.re();
imgamatrix3[i5*row1+i6]=WFn.im();//除对角线上其它位置元素为零,本次无需在相应位置附零
}
}
}
Dmatrix.newmatrix(row1,row1,realmatrix3,imgamatrix3);//row1不能超过为4096,但是可以为2048,newmatrix有限制
Complexmatrix[] Fnenconjugate1=new Complexmatrix[n/(int)Math.pow(2,i4+1)];
// }//临时补一个反括号
/*
for(int i8=0;i7<(int)(Math.pow(2,i4));i7++){
}*/
//Dmatrix
if(i4==0){
double[] realmatrix4=new double[n/(int)Math.pow(2,i4)];
double[] imgamatrix4=new double[n/(int)Math.pow(2,i4)];
for(int i11=0;i11<n;i11++){
for(int i9=0;i9<1;i9++){
for(int i10=0;i10<1;i10++){
//realmatrix4[i9*1+i10]=P[i9*1+i10][0];//short转为double
realmatrix4[i9*1+i10]=(double)P[i11][i9*1+i10]/65536;//short转为double,把P[i9*1+i10][0]改成了P[i11][i9*1+i10]多除以了65536,最后还是要除以65536,再填上(double)
// realmatrix4[i9*1+i10]=0;
imgamatrix4[i9*1+i10]=0;
//Fnconjugate0=Fnenconjugate;
}
}
// Fnenconjugate[i11].newmatrix((int)(n/Math.pow(2,i4)),1,realmatrix4,imgamatrix4);
Fnenconjugate[i11]=new Complexmatrix();
Fnenconjugate[i11].newmatrix(1,1,realmatrix4,imgamatrix4);//在生成矩阵前要先实例化对象
}//上面都对
}
for(int i13=0;i13<(int)(n/Math.pow(2,i4+1));i13++){
// Fnenconjugate[i11].get(2*(i13+1),1).ti
// Dmatrix.AtimesB(Fnenconjugate[i13*2+1]);//增加矩阵函数返回给B
Fnenconjugate[i13*2+1].BbyAtimes(Dmatrix);
// Fnenconjugate1[i13]=Fnenconjugate[i13*2].AaddB(Fnenconjugate[i13*2+1])
Complexmatrix complexmatrx1=Fnenconjugate[i13*2].AaddB(Fnenconjugate[i13*2+1]);
Complexmatrix complexmatrix2=Fnenconjugate[i13*2].AsubB(Fnenconjugate[i13*2+1]);
//先实例化对象
Fnenconjugate1[i13]=new Complexmatrix();
Fnenconjugate1[i13]=complexmatrx1.rowcombine(complexmatrx1,complexmatrix2);
// Fnenconjugate[i13*2
// Fnenconjugate[i13*2].add0
}
Fnenconjugate=Fnenconjugate1;
if(i4==m-1){
Fn=Fnenconjugate[0];
}
}
//Fnconjugate0=Fnenconjugate;
// Fnconjugate0=Fnenconjugate;
/*
for(int i=0;i<n;i++){
for(int j=0;j<0;j++){
realmatrix1[i*n+j]=w.re();
}
}
for(int i1=0;i1<n;i1++){
for(int j1=0;j1<n;j1++){
imagmatrix[i1*n+j1]=
imgamatrix1[i1*n+j1]=w.re();
}
}*/
//Complexmatrix Fn=new Complexmatrix();
//Fn取共轭
Fn.conjugate();
int costtime1=(int) System.currentTimeMillis()-currentTimeMillis;//得出计算花费的时间
//根据FFT结果产生幅值和角度值数据,和FFT函数相同方法
double[] length=new double[n];
double[] angle=new double[n];
for(int i5=0;i5<n;i5++){
for(int j5=0;j5<1;j5++){
//Fn.get(i5*1+j5+1,1).re()*Fn.get(i5*1+j5
length[i5]=Math.sqrt(Fn.get(i5*1+j5+1,1).re()*Fn.get(i5*1+j5+1,1).re()+Fn.get(i5*1+j5+1,1).im()*Fn.get(i5*1+j5+1,1).im());//再开方得到复数的模
if(Fn.get(i5*1+j5+1,1).re()!=0){
// angle[i5]=Math.atan(Fn.get(i5+1,1).im()/Fn.get(i5+1,j5).re());//得到复数的主值,考虑实部和虚部正负性
try{
if(Fn.get(i5*1+j5,1).re()>0){
//angle[i5]=Math.atan(Fn.get(i5*1+j5)
angle[i5]=Math.atan(Fn.get(i5*1+j5,1).im()/Fn.get(i5*1+j5,1).re());
}else{
if(Fn.get(i5*1+j5,1).im()>=0){
angle[i5]=Math.atan(Fn.get(i5*1+j5,1).im()/Fn.get(i5*1+j5,1).re())+Math.PI;
}else{
angle[i5]=Math.atan(Fn.get(i5*1+j5,1).im()/Fn.get(i5*1+j5,1).re())-Math.PI;
}
}
}catch(Exception e){}
}else{
if(Fn.get(i5*1+j5+1,1).im()>0){
angle[i5]=Math.PI/2;
}else{
if(Fn.get(i5*1+j5+1,1).im()<0){
angle[i5]=Math.PI*(-1)*0.5;
}else{
angle[i5]=0;
}
}
}
}
}
double[] range=new double[n];//range是幅度
for(int i6=0;i6<n;i6++){
for(int j6=0;j6<1;j6++){
range[i6*1+j6]=20*Math.log10(length[i6*1+j6]);
}
}
//得到的range为幅度,angle为角度
//将幅度和角度与频率的关系画成Bode图得出频谱分析图
//频谱特性图
double[] axis=new double[n];
for(int i=0;i<n;i++){
axis[i]=i*Wb;
}
//byte[] bitebyte1=bitbyte(angle,range,axis);左边这行代码不能用
byte[] bitebyte1=new byte[320*240*4];
for(int i2=0;i2<240;i2++){
//选择生成Bitmap的类型
int height=(int)(180-(angle[i2]*180/Math.PI+180)*0.5+30);//转换成弧度制,这里是生成相频曲线图
//int height=(int)(180-(range[i2]+180)*0.5+30);//幅频特性Bode图,单位为分贝db,这里是生成幅频曲线图
//int height=(int)(180-(length[i2]+180)*0.5+30);//复数求模所得的幅频图,取对数并乘以20后得到以分贝为单位的幅频特性Bode图,这里是另一种图像
int width=(int)(40+i2);
for(int j2=0;j2<320;j2++){
for(int k2=0;k2<4;k2++){
if(height>=0&&height<120){
for(int i4=0;i4<120-height;i4++){
switch(k2){
case 0:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-1;//-1的补码为11111111
}break;
case 1:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-18;//-18的补码为0xee;
}break;
case 2:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-18;
}break;
case 3:{
bitebyte1[(height+i4)*320*4+width*4+k2]=-1;
}break;
}
}
}else{
if(height>=120&&height<210){
for(int i4=0;i4<height-120;i4++){
switch(k2){
case 0:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-1;//-1的补码为11111111
}break;
case 1:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-18;//-18的补码为0xee;
}break;
case 2:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-18;
}break;
case 3:{
bitebyte1[(height-i4)*320*4+width*4+k2]=-1;
}break;
}}}
}
}
}
}
Bitmap bmp0=Bitmap.createBitmap(320,240,Bitmap.Config.ARGB_8888);
int[] bmpint=new int[240*320];
for(int i=0;i<240*320;i++){
for(int j=0;j<4;j++){
// bmpint[i]=bitebyte1[i*4+j];
try{
switch(j){
case 0:{
bmpint[i]=bitebyte1[i*4+j]&0xff;
//bmpint[i]=0xffffee00;
}break;
case 1:{
bmpint[i]+=(bitebyte1[i*4+j]&0xff)<<8;
}break;
case 2:{
bmpint[i]+=(bitebyte1[i*4+j]&0xff)<<16;
}break;
case 3:{
bmpint[i]+=(0xff&0xff)<<24;//int型产量左移一定位数,并实现byte[4]转int型
}break;
}
}catch(Exception e){
}
}
}
//bmp0.setp
bmp0.setPixels(bmpint,0,320,0,0,320,240);
bmp1=BitmapFactory.decodeByteArray(bitebyte1,0,240*320*4);
Bitmap bmp1=null;//检查问题,已排除问题,然而并没有
double[][] databyFFT=new double[3][];
databyFFT[0]=angle;
databyFFT[1]=range;
databyFFT[2]=axis;
// return databyFFT;
return bmp0;
// return angle;
//return null;
}
public boolean BbyAtimes(Complexmatrix A){
if(this.row==A.getcol()){
//this.col=complexmatrixB.getcol();一开始不能改变本地矩阵的列数
/*
double[] newrealmatrix=new double[this.col*A.getrow()];
double[] newimagmatrix=new double[this.col*A.getrow()];
for(int i=0;i<A.getrow();i++){
for(int j=0;j<this.col;j++){
double im2=0;
double re2=0;
Complex complex0=new Complex(0,0);
for(int j1=0;j1<A.getcol();j1++){
// Complex complex2=complex0;
Complex complex1=A.get(i+1,j1+1).times(this.get(j1+1,j+1));
complex0=complex0.plus(complex1);
}
// this.set(i,j,complex0);
im2=complex0.im();
re2=complex0.re();
newrealmatrix[i*this.getcol()+j]=re2;
newimagmatrix[i*this.getcol()+j]=im2;
}
}
this.newmatrix(A.getrow(),this.getcol(),newrealmatrix,newimagmatrix);
*/
//改进为对角矩阵乘以单位列向量形式
double[] newrealmatrix=new double[this.col*A.getrow()];
double[] newimagmatrix=new double[this.col*A.getrow()];
for(int i=0;i<A.getrow();i++){
for(int j=0;j<1;j++){
double im2=0;
double re2=0;
Complex complex0=new Complex(0,0);
//for(int j1=0;j1<A.getcol();j1++){
// Complex complex2=complex0;
// Complex complex1=A.get(i+1,j1+1).times(this.get(j1+1,j+1));
complex0=A.get(i+1,i+1).times(this.get(i+1,1));
//complex0=complex0.plus(complex1);
//}
// this.set(i,j,complex0);
im2=complex0.im();
re2=complex0.re();
newrealmatrix[i]=re2;
newimagmatrix[i]=im2;
}
}
this.newmatrix(A.getrow(),1,newrealmatrix,newimagmatrix);
return true;
}else{
return false;
}
}
public Complexmatrix AsubB(Complexmatrix B){
if(this.row==B.getrow()&&(this.col==B.getcol())){
double[] realmatrix1=new double[this.row*this.col];
double[] imgamatrix1=new double[this.row*this.col];
for(int i=0;i<this.row;i++){
for(int j=0;j<this.col;j++){
/*
this.realmatrix[i*this.col+j]+=-B.realmatrix[i*this.col+j];
this.imagmatrix[i*this.col+j]+=-B.imagmatrix[i*this.col+j];*/
realmatrix1[i*this.col+j]=this.realmatrix[i*this.col+j]-B.realmatrix[i*this.col+j];
imgamatrix1[i*this.col+j]=this.imagmatrix[i*this.col+j]-B.imagmatrix[i*this.col+j];
}
}
// return true;
Complexmatrix complexmatrix1=new Complexmatrix();
complexmatrix1.newmatrix(this.row,this.col,realmatrix1,imgamatrix1);
return complexmatrix1;
}else{
return null;
}
}
public Complexmatrix AaddB(Complexmatrix B){
if(this.row==B.getrow()&&(this.col==B.getcol())){
double[] realmatrix1=new double[this.row*this.col];
double[] imgamatrix1=new double[this.row*this.col];
for(int i=0;i<this.row;i++){
for(int j=0;j<this.col;j++){
realmatrix1[i*this.col+j]=this.realmatrix[i*this.col+j]+B.realmatrix[i*this.col+j];
imgamatrix1[i*this.col+j]=this.imagmatrix[i*this.col+j]+B.imagmatrix[i*this.col+j];
}
}
Complexmatrix complexmatrix1=new Complexmatrix();
complexmatrix1.newmatrix(this.row,this.col,realmatrix1,imgamatrix1);
return complexmatrix1;
}else{
return null;
}
}
public Complexmatrix rowcombine(Complexmatrix A,Complexmatrix B){
Complexmatrix C=new Complexmatrix();
if(A.getcol()==B.getcol()){
double[] realmatrix1=A.realmatrix;
double[] imgamatrix1=A.imagmatrix;
double[] realmatrix2=B.realmatrix;
double[] imgamatrix2=B.imagmatrix;
double[] realmatrix3=new double[(A.getrow()+B.getrow())*A.getcol()];
double[] imgamatrix3=new double[(A.getrow()+B.getrow())*A.getcol()];
/*
for(int i=0;i<(A.getrow()+B.getrow());i++){
for(int j=0;j<A.getcol();j++){
realmatrix3[i*A.getcol()+j]=
}
}
*/
int row1=A.getrow();
int row2=B.getrow();
int col1=A.getcol();
for(int i=0;i<row1;i++){
for(int j=0;j<col1;j++){
realmatrix3[i*col1+j]=realmatrix1[i*col1+j];
imgamatrix3[i*col1+j]=imgamatrix1[i*col1+j];
}
}
for(int i1=0;i1<row2;i1++){
for(int j1=0;j1<col1;j1++){
realmatrix3[(row1+i1)*col1+j1]=realmatrix2[i1*col1+j1];
imgamatrix3[(row1+i1)*col1+j1]=imgamatrix2[i1*col1+j1];
}
}
C.newmatrix(row1+row2,col1,realmatrix3,imgamatrix3);
return C;
}else{
return null;
}
}
//for(int i1=0;i1<n;i1++){
//}
/*
//用bitmap画bode图方法
public Bitmap bodebmp(){
Bitmap bmp1=BitmapFactory.decodeByteArray();
}
static System.loadLibrary("helloapp");
*/
static{
System.loadLibrary("helloapp");
}
private int row;
private int col;
private double[] realmatrix;
private double[] imagmatrix;
}
5.主要的方法为FFT和getanglebyFFT,具体算法看函数里的注释说明,这里不再详细阐述,下面是效果图:
6.好了,新人经验不多,很多没说明清楚的还希望各位CSDN大神海涵,批评指出不当之处