调用 libsac 库

next2

SAC在做 FFT 时要保证数据点数为 \(2^n\) 个,对于不足 \(2^n\) 个点的数据需要补零至 \(2^n\) 次方个点。

next2 函数定义为:

int next2(int num)  // 输入为 num,返回值为大于 num 的最小2次幂

xapiir

xapiir 用于设计IIR滤波器,并对数据进行滤波。这个子函数底层调用了 designapply 两个子函数。

void xapiir(float  *data,      // 待滤波的数据,滤波后的数据保存在该数组中
            int     nsamps,    // 数据点数
            char   *aproto,    // 滤波器类型
                               //  - 'BU': butterworth
                               //  - 'BE': bessel
                               //  - 'C1': chebyshev type I
                               //  - 'C2': chebyshev type II
            double  trbndw,    // chebyshev 滤波器的过渡带宽度
            double  a,         // chebyshev 滤波器的衰减因子
            int     iord,      // 滤波器阶数
            char   *type,      // 滤波类型: 'LP','HP','BP','BR'
            double  flo,       // 低频截断频率
            double  fhi,       // 高频截断频率
            double  ts,        // 采样周期
            int     passes)    // 通道数,1或2

相关示例代码为 filterc.cfilterf.f

firtrn

firtrn 用于做数据应用 FIR 滤波器或对数据做 Hilbert 变换:

void firtrn(char  *ftype,     // 类型,取'HILBERT'或'DERIVATIVE'
            float *x,         // 输入数据
            int    n,         // 数据点数,至少含201个点
            float *buffer,    // 临时数组,长度至少4297
            float *y)         // 输出数组

下面的示例展示了如何计算数据的Hilbert变换:

#include <stdio.h>
#include <stdlib.h>
#define NPTS 1000

float *hilbert(float *in, int npts);

int main(){
    float data[NPTS];
    float *hdata;
    int i;
    // 准备输入数据
    for (i=0; i<NPTS; i++)  data[i] = i;
    // 进行Hilbert变换,hdata为Hilbert变换的结果
    hdata = hilbert(data, NPTS);
    for (i = 0; i < NPTS; i++)
        printf("%f\n", hdata[i]);

    free(hdata);
}

// 这里定义了hilbert函数,是对firtrn函数的一个封装
float *hilbert(float *in, int npts) {
    float *buffer;
    float *out;

    buffer = (float *)malloc(sizeof(float)*50000);
    out = (float *)malloc(sizeof(float)*npts);
    firtrn("HILBERT", in, npts, buffer, out);

    free(buffer);
    return out;
}

envelope

该子函数用于计算数据的包络函数,其底层调用了 firtrn 函数。

void envelope(int    n,     // 数据点数
              float *in,    // 输入数据
              float *out)   // 输出数据

需要注意,inout 不能是同一个数组。

相关示例代码为 envelopec.cenvelopef.f

crscor

该子函数用于计算两个数据的互相关,此互相关在频率域中完成,相对时间域互相关而言效率更高。

void crscor(float *data1,     // 数据1
            float *data2,     // 数据2
            int    nsamps,    // 数据点数
            int    nwin,      // 相关窗数目
            int    wlen,      // 窗内数据点数,最大值为2048
            char  *type,      // 窗类型,可以取'HAM','HAN','C','R','T'
            float *c,         // 输出数据,长度为2*wlen-1
            int   *nfft,      // 相关序列的数据点数
            char  *err,       // 错误消息
            int    err_s)     // 错误消息长度

示例代码为 convolvec.cconvolvef.fcorrelatec.ccorrelatef.f

rms

该子函数用于计算信号的均方根,其中计算公式为:

\[RMS = \sqrt{\sum_{i=1}^N y_i^2}\]

该公式与命令 rms 中的公式略有不同,严格来说,这里的定义是有问题的,因而对于该子程序计算出的结果,要除以根号 N 才是真正的均方根。

函数原型为:

double rms(float *x,            // 输入数据
           int nsamps)          // 数据点数

示例代码:

/*
 * 本例中使用 Prof. Lupei Zhu 的 sacio 库的数据读入子程序
 *
 * 编译方式:
 *    gcc prog.c sacio.c -lm -L/usr/local/sac/lib -lsac -lsacio
 */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "sac.h"

double rms(float *x, int nsamps);

int main() {
    SACHEAD hd;
    float *data;
    double result;

    data = read_sac("seis.SAC", &hd);
    result = rms(data, hd.npts)/sqrt(hd.npts);  // 除以根号N
    printf("rms = %lf\n", result);
}