Hàm nội suy 1 chiều và 2 chiều

tvduc

Thành viên mới
Tham gia ngày
12 Tháng chín 2007
Bài viết
5
Thích
1
Điểm
0
Tuổi
37
#4
Cảm ơn mọi người nhiều!minh không biết về VBA nhưng moi ngừoi có thể hướng dẫn cách lập biểu thứ nọi suy đo hay khong, và một bảng tính nào đó tôi muốn sử dụng nó thì làm thế nào, chẵng nhẽ mơ file nay lên rồi sửa trên đó hay sao?
cam on rất nhiều.
 

connhangheo

Thành viên thường trực
Tham gia ngày
18 Tháng năm 2007
Bài viết
214
Thích
216
Điểm
0
#5
cái này bạn phải biết 1 ít về VBA
Nếu bây h bạn có 1 bảng giá trị và cần tìm giá trị nội suy trong bảng đó thì bạn sẽ làm thực hiện như sau :
bạn phải biết công thức nó như thế nào đúng không :
- Với hàm nội suy 1 chiều thì công thức như sau :
=noisuy1(bảng giá trị, giá trị cần nội suy, thứ tự của cột cần lấy giá trị nội suy)
Tham số thứ 3 (thứ tự của cột cần lấy giá trị nội suy) cần dùng trong trường hợp bảng giá trị nội suy của bạn có nhiều cột. Ví dụ khi bạn khi bạn nội suy sức chịu tải tiêu chuẩn của đất dính (trong sách Cơ Học Đất) thì giá trị cần nội suy của bạn sẽ là hệ số rỗng e, nhưng vì có nhiều giá trị độ sệt IL khác nhau (mỗi giá trị là 1 cột) nên bạn cần phải biết thứ tự của cột là bạn cần lấy giá trị nội suy.
-Với hàm nội suy 2 chiều thì công thức là thế này:
=noisuy2(bảng giá trị,giá trị cần nộ suy thứ nhất, giá trị cần nội suy thứ 2)

hàm của mình nó chưa hoàn chỉnh, trong thời gian này mình đang phải làm nhiều bài tập TKMH và chuẩn bị ôn thi nên khá bận, khi nào có thời gian nhiều hơn mình sẽ học hỏi để hoàn thiện nó tốt hơn. Ví dụ như phần bắt lỗi mình cũng chưa làm,và còn 1 số cái khác nữa. Nhưng nếu dùng tạm thì cũng vẫn ổn. Mong mọi người góp ý và cũng hoàn thiện hàm này cho anh em trong forum học hỏi. Cảm ơn
 
Chỉnh sửa lần cuối bởi điều hành viên:

phhxd

Thành viên mới
Tham gia ngày
29 Tháng mười hai 2007
Bài viết
1
Thích
0
Điểm
0
Tuổi
32
#6
Mình đã dùng phần code của bạn, rất cám ơn :D Làm bài tập lớn cơ đất nhàn đi rất nhều!
Tuy nhiên trong quá trình làm mình thấy là khi giá trị của hàng ngang và dọc, chẳng may bằng và ứng với các giá trị của cột ngang đầu tiên và dọc đầu tiên là hàm sẽ làm việc ko ổn. Ví dụ cột dọc là 0.15 0.30 0.60; cột ngang là 0 0.25 0.5 Giá trị cần tra ở hàng ngang ứng với giá trị 0 là có vấn đề :)
Mình chưa có 1 tí kiến thức nào về VBA nên lần này may mắn tìm được bài viết của bạn, có điều thắc mắc như trên... Thank bạn :)
 

zigzag

Thành viên mới
Tham gia ngày
10 Tháng tư 2007
Bài viết
1
Thích
0
Điểm
663
#7
NSTT:
Function NSTT(xnew, xx, yy)
For i = 1 To xx.Count
If xx(i) > xnew Then
Exit For
End If
Next i
NSTT = (xnew - xx(i - 1)) / (xx(i) - xx(i - 1)) * (yy(i) - yy(i - 1)) + yy(i - 1)
End Function

đây là hàm nội suy tuyến tính 1 chiều! có bác nào viết cho tôi hàm tìm nghiệm của 1 pt được không! Cảm ơn!
 
Lần chỉnh sửa cuối:

duongthanh85

Thành viên mới
Tham gia ngày
14 Tháng mười hai 2006
Bài viết
8
Thích
2
Điểm
0
Tuổi
33
#8
Dùng hàm nội suy 2 chiều để tìm phương trình một mặt được không nhỉ?
Cụ thể là từ 1 dãy số liệu z(i)=F(x(i), y(i)
Để tìm ra dạng hàm của z=f(x,y)

Mong bạn có thể giúp mình, nếu có thể thì cả phần lý thuyết là tốt nhất. Cảm ơn!
 

PhanTuHuong

Excel & AutoCad & VBA & VB.NET
Thành viên danh dự
Tham gia ngày
13 Tháng sáu 2006
Bài viết
6,725
Thích
23,055
Điểm
1,860
#9
Hàm bạn connhangheo viết ổn đấy, cái khó nhất là tra vùng biên. Cứ thế phát huy --=0 !
Khai báo biến đầy đủ và chính xác (tôi thì hay nhầm và quên !$@!! ).
 

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia ngày
8 Tháng sáu 2006
Bài viết
5,081
Thích
8,715
Điểm
860
#10
Với nội suy 1 chiều, trước.

PHP:
Function noisuy1(vungtra As Range, X As Double, cot As Integer) As Double
    'ham noi suy 1 chieu
    Dim ktra As Boolean
    Dim i As Integer
    Dim x1 As Double, x2 As Double, y1 As Double, y2 As Double
    For i = 1 To vungtra.Cells.Count
     kiemtra = False
     If vungtra.Cells(i, 1) <= X And vungtra.Cells(i + 1, 1) >= X Then
      x1 = vungtra.Cells(i, 1): x2 = vungtra.Cells(i + 1, 1)
      y1 = vungtra.Cells(i, cot): y2 = vungtra.Cells(i + 1, cot)
      noisuy1 = (y2 - y1) * (X - x1) / (x2 - x1) + y1
      ktra = True
     End If
    Next i
    If ktra = False Then
     MsgBox "gia tri can tim ko nam trong bang tra", vbInformation
     Exit Function
    End If
End Function
Bạn còn phí phạm tài nguyên & thời giờ:
Khi tìm ra hàm rồi, nên thoát ngay vòng lặp/thoát ngay hàm, cũng OK!

Cái này mình chỉ mới suy đón thôi, cũng mạnh dạn nêu ra đây:
Nếu giá trị các cột là tăng (Giảm dần) & trong cột cũng tăng dần
có nghĩa là
1 8
2 14
7 15
thì bạn nên duyệt hàng đầu trước đề tìm trị trong ô nào > X;
Sau khi tìm ra, ta quay lại cột trước đó & tìm trong cột đó thôi.
 
Lần chỉnh sửa cuối:

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia ngày
8 Tháng sáu 2006
Bài viết
5,081
Thích
8,715
Điểm
860
#11
Xin giới thiệu 1 cách khác để lập hàm nội suy 2 chiều

* Nhược điểm lớn nhất của hàm nội suy 2 chiều ( tại #1) là vòng lặp thứ hai lại phải duyệt toàn bộ các cells trong vùng chọn. Nhưng thực chất ta chỉ cần:
- Ở vòng lặp đầu tạm chấp nhận vì duyệt chỉ trong hàng đầu
- Vòng sau chỉ cần duyệt cột đầu của vùng dữ liệu; Vì ta đã khai báo 2 biến dạng Range (Rng & Clls), nên lưu trong nó (kèm theo 1 cách đương nhiên) các trị số cột & hàng của chúng.

PHP:
Option Explicit
Function NoiSuyGPE(VungTra As Range, xX As Double, yY As Double) As Double
    'Ham Noi Suy 2 Chieu Tai GPE.COM (Sa_DQ)'
    Dim iW As Integer, jI As Integer
    Dim x1 As Double, x2 As Double, y1 As Double, y2 As Double
    Dim a11 As Double, a12 As Double, a21 As Double, a22 As Double
    Dim t1 As Double, t2 As Double
    
    Dim RgNg As Range, RgDoc As Range
    Dim Rng As Range, Clls As Range
    Set RgNg = VungTra.Cells(1, 1).Resize(1, VungTra.Columns.Count - 1)
    Set RgDoc = VungTra.Cells(1, 1).Resize(VungTra.Rows.Count, 1)
    
1    For Each Rng In RgNg
2      If Rng <= yY And Rng.Offset(, 1) >= yY Then
3        y1 = Rng:           y2 = Rng.Offset(, 1)
        For Each Clls In RgDoc
5        If Clls <= xX And Clls.Offset(1) >= xX Then
         x1 = Clls:         x2 = Clls.Offset(1)
        '3*'
7       a11 = Cells(Clls.Row, Rng.Column):  a12 = Cells(Clls.Row, Rng.Column + 1)
        a21 = Cells(Clls.Row + 1, Rng.Column): a22 = Cells(Clls.Row + 1, Rng.Column + 1)
9         t1 = (a12 - a11) * (yY - y1) / (y2 - y1) + a11
         t2 = (a22 - a21) * (yY - y1) / (y2 - y1) + a21
11         NoiSuyGPE = (t2 - t1) * (xX - x1) / (x2 - x1) + t1
         Exit For
13        End If
        Next Clls
15      End If
    Next Rng
17    If NoiSuyGPE = 0 Then  '!'
        msgbox "gia tri can tim ko nam trong bang tra", vbInformation
19    End If
End Function
 

hung1981

Thành viên mới
Tham gia ngày
20 Tháng mười hai 2006
Bài viết
15
Thích
2
Điểm
0
Tuổi
37
#12
connhangheo đã viết:
hàm của mình nó chưa hoàn chỉnh, trong thời gian này mình đang phải làm nhiều bài tập TKMH và chuẩn bị ôn thi nên khá bận, khi nào có thời gian nhiều hơn mình sẽ học hỏi để hoàn thiện nó tốt hơn. Ví dụ như phần bắt lỗi mình cũng chưa làm,và còn 1 số cái khác nữa. Nhưng nếu dùng tạm thì cũng vẫn ổn. Mong mọi người góp ý và cũng hoàn thiện hàm này cho anh em trong forum học hỏi. Cảm ơn
Mình đã thử hàm của bạn rồi
Nó có một nhược điểm là tra 1 chiều cùng tăng hay thì được nhưng khi x tăng mà y giảm thì chịu thua
Mình đã nghiên cứu sửa lại
chỗ
For i = 1 To vungtra.cells.count
thành
For i = 1 To vungtra.Rows.Count
thì chạy ok
Không biết góp ý của mình có đúng hay không
Chúng ta cùng thảo luận nhé
 

hung1981

Thành viên mới
Tham gia ngày
20 Tháng mười hai 2006
Bài viết
15
Thích
2
Điểm
0
Tuổi
37
#13
connhangheo đã viết:
em xin giải thích hàm của em như sau, mọi người cho ý kiến về code giúp em
Hàm noisuy2 bạn mắc lỗi giống hàm nội suy 1 chỗ chọn giá trị vòng lặp
Mình edit lại thấy chạy tốt hơn
Bạn thử xem
 

SA_DQ

/(hông là gì!
Thành viên danh dự
Tham gia ngày
8 Tháng sáu 2006
Bài viết
5,081
Thích
8,715
Điểm
860
#14
Tự cải tiến tiếp tục:

Quan sát dòng lệnh 9 & 10 mình thấy còn có thể rút gọn thêm (về cách viết) để đỡ rườm rà. Đó là tính trước 2 biểu thức, như sau
Tính trước cho y2: tại phần sau của dòng lệnh 3 sẽ là
y2 = Rng.Offset(, 1) - y1
Tương tự như vậy, tại phần sau của dòng lệnh 7 sẽ là:
a12 = Cells(Clls.Row, Rng.Column + 1) - a11
& tại phần sau của dòng lệnh 8 là:
a22 = Cells(Clls.Row + 1, Rng.Column + 1) - a12
Sau đó trông vô 2 biểu thức tại dòng lệnh 9 & 10 dẻ thiện cảm hơn!
, như sau:
PHP:
                         t1 = (a12 ) * (yY - y1) / (y2 ) + a11
 t2 = (a22 ) * (yY - y1) / (y2 ) + a21
Vấn đề nữa là: Dòng lệnh 17 còn phải viết lại cho chuẩn hơn!. . . .
Sau cùng: Mình còn dư 2 biến khai báo chưa dùng (Do lịch sử để lại!)

Mã:
Option Explicit
[B]Function NoiSuyGPE(VungTra As Range, xX As Double, yY As Double) As Double[/B]  
 [COLOR="Blue"] 'Ham Noi Suy 2 Chieu Tai GPE.COM (Sa_DQ)'[/COLOR] 
   [COLOR="Silver"]Dim iW As Integer, jI As Integer[/COLOR]
    Dim x1 As Double, x2 As Double, y1 As Double, y2 As Double
    Dim a11 As Double, a12 As Double, a21 As Double, a22 As Double
    Dim t1 As Double, t2 As Double
    
    Dim RgNg As Range, RgDoc As Range
    Dim Rng As Range, Clls As Range
    Set RgNg = VungTra.Cells(1, 1).Resize(1, VungTra.Columns.Count - 1)
    Set RgDoc = VungTra.Cells(1, 1).Resize(VungTra.Rows.Count, 1)
    
1    For Each Rng In RgNg
2      If Rng <= yY And Rng.Offset(, 1) >= yY Then
3        y1 = Rng:         [COLOR="Silver"]  y2 = Rng.Offset(, 1)[/COLOR]  
      For Each Clls In RgDoc
5        If Clls <= xX And Clls.Offset(1) >= xX Then
         x1 = Clls:         x2 = Clls.Offset(1)
        '3*'
7       a11 = Cells(Clls.Row, Rng.Column):  [COLOR="silver"]a12 = Cells(Clls.Row, Rng.Column + 1)[/COLOR]       
       a21 = Cells(Clls.Row + 1, Rng.Column): [COLOR="silver"]a22 = Cells(Clls.Row + 1, Rng.Column + 1)[/COLOR]
9        [COLOR="silver"] t1 = (a12 - a11) * (yY - y1) / (y2 - y1) + a11
         t2 = (a22 - a21) * (yY - y1) / (y2 - y1) + a21[/COLOR]
11         NoiSuyGPE = (t2 - t1) * (xX - x1) / (x2 - x1) + t1
         Exit For
13        End If
        Next Clls
15      End If
    Next Rng
17    If NoiSuyGPE = 0 Then  '!'
        msgbox "gia tri can tim ko nam trong bang tra", vbInformation
19    End If
End Function
 
Lần chỉnh sửa cuối:

vietlge

Thành viên mới
Tham gia ngày
22 Tháng mười 2008
Bài viết
11
Thích
0
Điểm
0
Tuổi
34
#15
Chào bác Connhangheo!
em down cái file excel tính hàm nội suy 1 chiều và 2 chiều về tính toán!
kết quả tốt lắm
nhưng mà bác ơi! Không hiểu sao khi vùng tra nằm tại một số ô trên Work sheet thì không thực hiện được 2 hàm trên. Khi mình cop vùng tra ra chỗ khác vẫn trên work sheet đó thì lại làm được.
Kể cả khi vùng tra ok rồi thực hiện phép tính ok rồi nhưng nếu mình xóa một ô or một cột nào đó mà ko ảnh hưởng đến vùng tra đó thì hàm tính tự nhiên lại ko tính được nữa.
mình không hiểu thế là thế nào? bạn có thể giải thích cho mình và hướng dẫn mình cách giải quyết ko?
mình nghĩ do macro bị virus bởi vì khi bật file excel lên thì thấy có dòng chữ:
Macros may contain viruses!....
Mình phải làm sao đây?
giúp mình nhé!
Cảm ơn and best regards!

chào bác connhangheo!
em insert hai cái code của bác vào dùng thử thấy tốt! nhưng mà có một vấn đề là trên work sheet ý, khi vùng tra ở một ô nào đó thì không thực hiện được hai hàm đó bác ạ
còn khi em cop vùng tra ra chỗ khác vẫn trên sheet đó thì lại thực hiện được
nó như thế nên rất khó để trình bày
như thế có phải là do macros của bác bị virus ko?
hay là bị vấn đề gì? mong bác giải quyết hộ vấn đề này!
cảm ơn bác nhiều!
 
Chỉnh sửa lần cuối bởi điều hành viên:

dangvutuan

Thành viên mới
Tham gia ngày
10 Tháng mười 2006
Bài viết
7
Thích
8
Điểm
0
#17
Mình là dân kỹ thật nên sử dụng nội suy từ rất lâu (từ năm 1998) nên cũng đã viết ra hàm nội suy để dùng riêng. Cũng phải qua thực tế sử dụng rất nhiều lần mới viết được một hàm ưng ý (vì trong lĩnh vực kỹ thuật rất cần sự chính xác và tin cậy), tiện đây xin giới thiệu để các bạn tham khảo:
' One Directions Interpolate Function
' Author : Dang Vu Tuan
'
Function NS(table_array, Lookup_value)
Dim NumRows As Integer, i As Integer
Dim Max, Min
Dim Range1 As Range, Range2 As Range

NumRows = table_array.Rows.Count
Set Range1 = table_array.Columns(1)
Set Range2 = table_array.Columns(2)
' check for case if val = last value in range1
If Lookup_value = Range1.Cells(NumRows) Then
NS = Range2.Cells(NumRows)
Exit Function
End If
' Get Max and Min
Max = Range1.Cells(1)
Min = Range1.Cells(1)
For i = 1 To NumRows
If Max <= Range1.Cells(i) Then Max = Range1.Cells(i)
If Min >= Range1.Cells(i) Then Min = Range1.Cells(i)
Next i
' Return an error if lookup_value is not within range1
If Lookup_value > Max Or Lookup_value < Min Then
NS = "Out of range" 'Evaluate("NA()")
Exit Function
End If
' Do linear interpolation
For i = 1 To NumRows - 1
If (Lookup_value >= Range1.Cells(i) And Lookup_value <= Range1.Cells(i + 1)) Or (Lookup_value <= Range1.Cells(i) And Lookup_value >= Range1.Cells(i + 1)) Then
If (Range1.Cells(i) - Range1.Cells(i + 1)) <> 0 Then
NS = (Range2.Cells(i + 1) + (Range2.Cells(i) - Range2.Cells(i + 1)) * (Lookup_value - Range1.Cells(i + 1)) / (Range1.Cells(i) - Range1.Cells(i + 1)))
Else
NS = Range2.Cells(i)
End If
Exit Function
End If
Next i
End Function



Và đây là hàm nội suy hai chiều:

' Two Directions Interpolate Function
' Author : Dang Vu Tuan
'
Function NS2(Data_Range As Range, x, y)
Dim A(), xMax, yMax, xMin, yMin
Dim Nx, Ny, i, J, k1, k2, k3, k4, k12, k34
'Get the data
Nx = Data_Range.Columns.Count
Ny = Data_Range.Rows.Count
ReDim A(Nx, Ny)
For i = 1 To Nx
For J = 1 To Ny
A(i, J) = Data_Range(J, i)
Next J
Next i
'Check data
xMax = A(2, 1)
xMin = A(2, 1)
For i = 2 To Nx
If xMax < A(i, 1) Then xMax = A(i, 1)
If xMin > A(i, 1) Then xMin = A(i, 1)
Next i
yMax = A(1, 2)
yMin = A(1, 2)
For J = 2 To Ny
If yMax < A(1, J) Then yMax = A(1, J)
If yMin > A(1, J) Then yMin = A(1, J)
Next J
If x < xMin Or x > xMax Or y < yMin Or y > yMax Then
NS2 = "Out of range"
Exit Function
End If
'Do linear interpolation
For i = 2 To Nx - 1
If (A(i, 1) <= x And x <= A(i + 1, 1)) Or (A(i, 1) >= x And x >= A(i + 1, 1)) Then
For J = 2 To Ny - 1
If (A(1, J) <= y And y <= A(1, J + 1)) Or (A(1, J) >= y And y >= A(1, J + 1)) Then
k1 = A(i, J)
k2 = A(i + 1, J)
k3 = A(i, J + 1)
k4 = A(i + 1, J + 1)
If (A(i + 1, 1) - A(i, 1)) = 0 Then
k12 = k1
k34 = k3
Else
k12 = k1 + (k2 - k1) * (x - A(i, 1)) / (A(i + 1, 1) - A(i, 1))
k34 = k3 + (k4 - k3) * (x - A(i, 1)) / (A(i + 1, 1) - A(i, 1))
End If
If (A(1, J + 1) - A(1, J)) = 0 Then
NS2 = k12
Else
NS2 = k12 + (k34 - k12) * (y - A(1, J)) / (A(1, J + 1) - A(1, J))
End If
Exit Function
End If
Next J
End If
Next i
End Function



Hai hàm trên mình viết để dễ theo dõi nên thực sự còn có thể compact được hơn nữa.
 

duong0h5

Thành viên mới
Tham gia ngày
10 Tháng tư 2009
Bài viết
5
Thích
1
Điểm
0
Tuổi
31
#18
Mình đang cần cái này rất gấp
mình đã tải file về
nhưng kô biết cách nào để đưa hàm nội suy vào bảng tính của mình được còn bảng tính của bạn thì ok
để tiện cho việc tra, mình co thể để nó ở từng SHEET của excel được kô
 

newcomer007

Thành viên mới
Tham gia ngày
8 Tháng ba 2009
Bài viết
4
Thích
1
Điểm
0
#19
mình đã down file của ban về nhưng không dùng được, no bị lỗi #Name, chac do minh thieu cài chi đó đúng không?bạn nào help mình với, Cảm ơn alot
 

ptlong04x1

Thành viên tích cực
Tham gia ngày
15 Tháng mười 2008
Bài viết
1,031
Thích
1,518
Điểm
860
Tuổi
34
#20
mình đã down file của ban về nhưng không dùng được, no bị lỗi #Name, chac do minh thieu cài chi đó đúng không?bạn nào help mình với, Cảm ơn alot
Bạn vào Tools\Macro\Security --> chọn Medium, sau này nếu mở file ra Excel có hỏi gì đó thì bạn phải chọn Enable Macro.
 
Top