Skip to content

Total same code but in totally different behavior #135

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
ElinLiu0 opened this issue Jun 10, 2025 · 2 comments
Closed

Total same code but in totally different behavior #135

ElinLiu0 opened this issue Jun 10, 2025 · 2 comments

Comments

@ElinLiu0
Copy link

Hi:
I'm using below Numpy.NET code to interpolate an NDarray:

public NDarray interpolate_f0(NDarray f0)
{
    int N = f0.shape[0];
    if (np.all(f0 <= 0))
    {
        return np.zeros_like(f0);
    }
    // 获取所有F0点位置
    NDarray nz = np.nonzero(f0 > 0)[0];
    // 如果只有一个非零点,返回该点的值
    if (nz.size == 1)
    {
        return np.full_like(f0, f0[nz[0]].GetData<float>()[0]);
    }
    // 每个位置在nz中的插入点索引
    NDarray pos = np.arange(N);
    NDarray idx = np.searchsorted(nz,pos,side: "left");

    // 限制idx范围
    int max_i = nz.size - 1;
    NDarray idx_low = np.clip(idx - 1, np.array(0), np.array(max_i));
    NDarray idx_high = np.clip(idx,np.array(0), np.array(max_i));

    // 左右端点在原数组中的索引
    NDarray left_idx = nz[idx_low];
    NDarray right_idx = nz[idx_high];

    // 两段的值
    NDarray left_val = f0[left_idx];
    NDarray right_val = f0[right_idx];

    // 计算分母避免除0
    NDarray demon = (right_idx - left_idx).astype(np.float64);
    demon = np.where(np.array(demon == np.array(0)),np.array(1),demon);

    // 插值比例
    NDarray t = (pos - left_idx).astype(np.float64) / demon;
    // 计算插值结果
    NDarray output = left_val + t * (right_val - left_val);

    // 原非零位置保持不变
    output = np.where(np.array(f0 > 0), f0, output);
    return output;
}

This code has the same Python version like:

def interpolate_numpy(f0: np.ndarray) -> np.ndarray:
    """
    输入 f0:1D numpy array
    输出:对 f0 中零值区间按照两端非零值做线性插值后的新数组
    """
    N = f0.shape[0]

    # 全部<=0,直接返回全零
    if np.all(f0 <= 0):
        return np.zeros_like(f0)

    # 找到所有>0的位置
    nz = np.nonzero(f0 > 0)[0]
    # 只有一个非零点,全部填该值
    if nz.size == 1:
        return np.full_like(f0, f0[nz[0]])

    # 每个位置在 nz 中的插入点索引
    pos = np.arange(N)
    idx = np.searchsorted(nz, pos, side='left')

    # 限制 idx_low, idx_high 到合法范围 [0, nz.size-1]
    max_i = nz.size - 1
    idx_low  = np.clip(idx - 1, 0, max_i)
    idx_high = np.clip(idx,     0, max_i)

    # 左右端点在原数组中的索引
    left_idx  = nz[idx_low]
    right_idx = nz[idx_high]

    # 两端的值
    left_val  = f0[left_idx]
    right_val = f0[right_idx]

    # 计算分母并避免除0
    denom = (right_idx - left_idx).astype(float)
    denom[denom == 0] = 1.0

    # 插值比例
    t = (pos - left_idx).astype(float) / denom

    # 线性插值
    out = left_val + t * (right_val - left_val)

    # 原非零位置保留原值
    out[f0 > 0] = f0[f0 > 0]

    return out

It should like: array([363. , 363. , 363. , ..., 76.3, 76.3, 76.3])
But it's actually got: Interpolated F0: [1.87585069e-309 1.17119999e+171 5.22741680e-037 ... nan
nan nan]

To make reproduce,please use library pyworld with below code:

f0,t = pyworld.dio(
    audio.astype(np.double),
    fs = 16000,
    f0_floor = 30,
    f0_ceil = 8000,
    frame_period = 1000 * 160 / 16000
)
f0:np.ndarray = pyworld.stonemask(audio.astype(np.double), f0, t, 16000)
for index, pitch in enumerate(f0):
    f0[index] = round(pitch, 1)

You can use any audio that you have and readed in librosa with sample rate 16000.

@ElinLiu0
Copy link
Author

Either below too:
C# Version:

private NDarray resize_f0(NDarray x,int target_len)
{
    NDarray source = np.array(x);
    source = np.where(source < 0.001,np.array(np.nan),source);
    var xp = np.arange(start: 0, stop: source.size).GetData<float>();
    var fp = source.GetData<float>();
    IReadOnlyCollection<float> xp_collection = xp;
    IReadOnlyCollection<float> fp_collection = fp;
    NDarray target = np.interp(x: np.arange(start: 0, stop: source.size * target_len,step: source.size / target_len),xp:xp_collection,fp:fp_collection);
    NDarray res = np.nan_to_num(target);
    return res;
}

Python Version:

def resize_f0(
    x : np.ndarray,
    target_len : int
) -> np.ndarray:
    """
    对F0进行重塑
    Args:
        x (np.ndarray): 输入F0
        target_len (int): 目标长度
    Returns:
        np.ndarray: 重塑后的F0
    """
    source:np.ndarray = np.array(x)
    source[source < 0.001] = np.nan
    target:np.ndarray = np.interp(
        np.arange(0, len(source) * target_len, len(source)) / target_len,
        np.arange(0, len(source)),
        source,
    )
    res:np.ndarray = np.nan_to_num(target)
    return res

@ElinLiu0
Copy link
Author

Looks like different input let it be i guess,close first : (

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant