Golang实现类似Matlab的插值功能

Golang实现类似Matlab的插值功能 我正在寻找这个函数 https://de.mathworks.com/help/matlab/ref/interp1.html

“interp1(x,v,xq)”

vq = interp1(x,v,xq) 使用线性插值返回一维函数在特定查询点处的插值。向量 x 包含样本点,v 包含对应的值 v(x)。向量 xq 包含查询点的坐标。如果你有多组在相同点坐标处采样的数据,那么你可以将 v 作为数组传递。数组 v 的每一列包含一组不同的一维样本值。

在 Go 语言中有实现吗?

这个 JavaScript 版本工作得很好

GitHub

Symmetronic/interp1

受 MATLAB 启发的一维数据插值。通过在 GitHub 上创建账户来为 Symmetronic/interp1 的开发做出贡献。

但也许已经有一个现成的 Go 版本了…

谢谢并致以最诚挚的问候


更新,我快速转换到了 Go 语言,目前运行良好 https://play.golang.org/p/VHLE-lLTx3A 这比我最初想的要简单…

func main() {
    fmt.Println("hello world")
}

更多关于Golang实现类似Matlab的插值功能的实战教程也可以访问 https://www.itying.com/category-94-b0.html

1 回复

更多关于Golang实现类似Matlab的插值功能的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


Go语言中虽然没有内置的插值库,但可以通过标准库实现类似Matlab的interp1线性插值功能。以下是完整的实现示例:

package main

import (
	"errors"
	"fmt"
	"sort"
)

// Interp1 实现一维线性插值
func Interp1(x, v []float64, xq []float64) ([]float64, error) {
	if len(x) != len(v) {
		return nil, errors.New("x和v长度必须相同")
	}
	if len(x) < 2 {
		return nil, errors.New("至少需要2个数据点")
	}

	// 检查x是否已排序,如未排序则创建排序副本
	if !sort.Float64sAreSorted(x) {
		sortedX := make([]float64, len(x))
		sortedV := make([]float64, len(v))
		copy(sortedX, x)
		copy(sortedV, v)
		
		sort.Slice(sortedX, func(i, j int) bool {
			return sortedX[i] < sortedX[j]
		})
		// 重新排列v以匹配排序后的x
		// 这里简化处理,实际需要根据索引重新映射
		x = sortedX
		v = sortedV
	}

	result := make([]float64, len(xq))
	
	for i, q := range xq {
		// 处理查询点超出范围的情况
		if q <= x[0] {
			result[i] = v[0]
			continue
		}
		if q >= x[len(x)-1] {
			result[i] = v[len(v)-1]
			continue
		}

		// 查找插值区间
		idx := sort.SearchFloat64s(x, q)
		if idx == 0 {
			idx = 1
		}

		// 线性插值公式: v = v0 + (v1 - v0) * (xq - x0) / (x1 - x0)
		x0, x1 := x[idx-1], x[idx]
		v0, v1 := v[idx-1], v[idx]
		
		result[i] = v0 + (v1-v0)*(q-x0)/(x1-x0)
	}
	
	return result, nil
}

func main() {
	// 示例数据
	x := []float64{1, 2, 3, 4, 5}
	v := []float64{10, 20, 30, 40, 50}
	xq := []float64{1.5, 2.5, 3.5, 4.5}

	// 执行插值
	vq, err := Interp1(x, v, xq)
	if err != nil {
		fmt.Printf("插值错误: %v\n", err)
		return
	}

	// 输出结果
	fmt.Println("查询点:", xq)
	fmt.Println("插值结果:", vq)
	
	// 验证: 在x=2.5处,期望值为25
	// 线性插值: 20 + (30-20)*(2.5-2)/(3-2) = 25
}

对于更复杂的插值需求(如样条插值、多项式插值),可以使用第三方库。以下是使用gonum库实现多种插值方法的示例:

package main

import (
	"fmt"
	"gonum.org/v1/gonum/interp"
)

func main() {
	// 使用gonum库的样条插值
	x := []float64{1, 2, 3, 4, 5}
	y := []float64{10, 20, 30, 40, 50}
	
	// 创建样条插值器
	spline := interp.NewLinear(x, y)
	
	// 查询点
	xq := []float64{1.5, 2.5, 3.5, 4.5}
	
	fmt.Println("样条插值结果:")
	for _, q := range xq {
		v, err := spline.Predict(q)
		if err != nil {
			fmt.Printf("在x=%v处插值失败: %v\n", q, err)
			continue
		}
		fmt.Printf("x=%.1f, v=%.2f\n", q, v)
	}
}

对于需要处理多维数据或矩阵的情况:

package main

import (
	"fmt"
	"gonum.org/v1/gonum/mat"
)

// Interp1Matrix 处理矩阵数据的插值(类似Matlab的矩阵输入)
func Interp1Matrix(x []float64, V *mat.Dense, xq []float64) (*mat.Dense, error) {
	r, c := V.Dims()
	if len(x) != r {
		return nil, fmt.Errorf("x长度(%d)必须等于矩阵行数(%d)", len(x), r)
	}

	// 创建结果矩阵
	result := mat.NewDense(len(xq), c, nil)

	for col := 0; col < c; col++ {
		// 提取当前列数据
		v := make([]float64, r)
		for i := 0; i < r; i++ {
			v[i] = V.At(i, col)
		}

		// 对每列进行插值
		vq, err := Interp1(x, v, xq)
		if err != nil {
			return nil, err
		}

		// 填充结果矩阵
		for i, val := range vq {
			result.Set(i, col, val)
		}
	}

	return result, nil
}

func main() {
	// 矩阵数据示例
	x := []float64{1, 2, 3, 4, 5}
	
	// 创建3列数据矩阵
	V := mat.NewDense(5, 3, []float64{
		10, 100, 1000,
		20, 200, 2000,
		30, 300, 3000,
		40, 400, 4000,
		50, 500, 5000,
	})
	
	xq := []float64{1.5, 2.5, 3.5}
	
	result, err := Interp1Matrix(x, V, xq)
	if err != nil {
		fmt.Printf("错误: %v\n", err)
		return
	}
	
	fmt.Println("矩阵插值结果:")
	fmt.Println(mat.Formatted(result))
}

安装gonum库:

go get gonum.org/v1/gonum

这些实现提供了类似Matlab interp1的功能,支持线性插值、边界处理,并能处理矩阵形式的多组数据。

回到顶部